728x90
스프린트를 진행하다보니 전체적인 구성을 이해하기 어려워서 한 줄 한 줄 정리해봄.
💡 server.token/index.js
// 환경 변수 사용하기, import dotenv from dotenv
require("dotenv").config();
// fs 모듈은 파일 시스템에 접근하는 모듈이다. 파일을 생성하거나 삭제하고 읽거나 쓸 수 있다.
const fs = require("fs");
// https 모듈 사용
const https = require("https");
// cors 모듈 사용
const cors = require("cors");
// 요청된 쿠키를 쉽게 추출할 수 있도록 도와주는 미들웨어인 cookie-parser 사용
const cookieParser = require("cookie-parser");
//express 사용
const express = require("express");
const app = express();
//사용자의 요청에 반응하는 컨트롤러 사용
const controllers = require("./controllers");
// express 4.16.0 버전에서는 express generator에 body-parser가 내장되어 있어 따로 설치하지 않아도 아래와 같은 방식을 사용 가능.
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// CORS 설정,
// origin: 도메인
// credentials: true로 설정해주어야 인증서가 동반이 돼 https 환경에서 통신이 가능하다.
// method: 요청에 사용될 메소드를 지정해주는 역할을 한다.
app.use(
cors({
origin: ["https://localhost:3000"],
credentials: true,
methods: ["GET", "POST", "OPTIONS"],
})
);
// 쿠키파서를 미들웨어에 추가
app.use(cookieParser());
//라우팅 설정
// /lonin 라우터에 대한 PUT 요청에 응답.
app.post("/login", controllers.login);
// /accesstokenrequest 라우터에 대한 GET 요청에 응답.
app.get("/accesstokenrequest", controllers.accessTokenRequest);
// /refreshtokenrequest 라우터에 대한 GET 요청에 응답.
app.get("/refreshtokenrequest", controllers.refreshTokenRequest);
// HTTPS_PORT -> 환경변수 안의 port가 아니면 4000번대 포트 이용.
const HTTPS_PORT = process.env.HTTPS_PORT || 4000;
// 인증서 파일들이 존재하는 경우에만 https 프로토콜을 사용하는 서버를 실행합니다.
// 만약 인증서 파일이 존재하지 않는경우, http 프로토콜을 사용하는 서버를 실행합니다.
// 파일 존재여부를 확인하는 폴더는 서버 폴더의 package.json이 위치한 곳입니다.
let server;
if (fs.existsSync("./key.pem") && fs.existsSync("./cert.pem")) {
const privateKey = fs.readFileSync(__dirname + "/key.pem", "utf8");
const certificate = fs.readFileSync(__dirname + "/cert.pem", "utf8");
const credentials = { key: privateKey, cert: certificate };
server = https.createServer(credentials, app);
server.listen(HTTPS_PORT, () => console.log("server runnning"));
} else {
server = app.listen(HTTPS_PORT);
}
module.exports = server;
💡 server.token/controllers/users/login.js
아직 에러코드가 헷갈린다.
200 -> 성공
400 -> 잘못된 요청. 서버가 요청의 구문을 인식하지 못함.
401 -> 권한 없음. 인증 안 됨. 인증 실패
403 -> 금지됨. 서버가 요청을 거부하고 있음. 사용자가 리소스에 대한 필요 권한을 갖고 있지 않다. 인가 실패!
더 많은 코드 들이 있지만, 다 외울 수 없기에 필요하면 이 링크 참고! https://ko.wikipedia.org/wiki/HTTP_%EC%83%81%ED%83%9C_%EC%BD%94%EB%93%9C
const { Users } = require("../../models");
//json web token 라이브러리를 사용해 토큰 생성.
const jwt = require("jsonwebtoken");
module.exports = async (req, res) => {
// TODO: urclass의 가이드를 참고하여 POST /login 구현에 필요한 로직을 작성하세요.
console.log(req.body.userId);
// 기본 구성은 이전 sprint인 im-sprint-auth-session 에서 가져옴.
// finidOne 함수를 이용해 id와 비밀번호 가져옴.
const userInfo = await Users.findOne({
where: { userId: req.body.userId, password: req.body.password },
});
//userinfo가 없을때
if (!userInfo) {
//404 에러 보내줌.
res.status(404).json({ data: null, message: "not authorized" });
}
// userinfo가 있을 때
else {
// payload 구성.
const payload = {
id: userInfo.id,
userId: userInfo.userId,
email: userInfo.email,
createdAt: userInfo.createdAt,
updatedAt: userInfo.updatedAt,
};
// jsonwebtoken 라이브러리를 사용해 토큰을 생성하는 방법은 아래와 같다.
// 옵션 같은 경우에는 다양하게 넣어줄 수 있는데 나는 아래와 같이 추가하였다.
var aT_options = {
expiresIn: "1d",
};
var rT_options = {
expiresIn: "3d",
issuer: "ejyoon",
subject: "userinfo",
};
const accessToken = jwt.sign(
payload,
process.env.ACCESS_SECRET,
aT_options
);
const refreshToken = jwt.sign(
payload,
process.env.REFRESH_SECRET,
rT_options
);
console.log("성공");
// res.cookies() 메소드를 통해 cookie 값 지정.
res.cookie("refreshToken", refreshToken);
res.status(200).send({
data: { accessToken: accessToken },
message: "ok",
});
}
};
💡 server.token/controllers/users/accessTokenRequest.js
const { Users } = require("../../models");
//json web token 라이브러리를 사용
const jwt = require("jsonwebtoken");
module.exports = (req, res) => {
// TODO: urclass의 가이드를 참고하여 GET /accesstokenrequest 구현에 필요한 로직을 작성하세요.
console.log(req.headers);
// authorization 헤더 확인 후 없으면 에러 전달
if (!req.headers.authorization) {
res.status(400).send({ data: null, message: "invalid access token" });
}
// 있으면 아래와 같이 수행
else {
const authorization = req.headers["authorization"];
//payload 암호화되어 있는 데이터 가져옴
const token = authorization.split(" ")[1];
// jwt.sign으로 암호화했다면, jwt.verify로 해독.
const data = jwt.verify(token, process.env.ACCESS_SECRET);
// console.log(data)
//데이터가 없으면 에러 전달
if (!data) {
res.status(403).send({
data: null,
message: "invalid access token",
});
}
// 데이터가 있다면 payload 데이터를 획득했으니, 각각의 값에 맞는 정보 찾아서 넣어줌.
else {
res.status(200).send({
data: {
userInfo: {
id: data.id,
userId: data.userId,
email: data.email,
createdAt: data.createdAt,
updatedAt: data.updatedAt,
},
},
message: "o",
});
}
}
};
💡 server.token/controllers/users/refreshTokenRequest.js
: accessTokenRequest와 거의 비슷하지만 리프레쉬 토큰으로 access 토큰을 재발급 받을 수 있음.
const { Users } = require("../../models");
//json web token 라이브러리를 사용
const jwt = require("jsonwebtoken");
module.exports = (req, res) => {
// TODO: urclass의 가이드를 참고하여 GET /refreshtokenrequest 구현에 필요한 로직을 작성하세요.
// 쿠키에서 refresh 토큰 가져옴.
const isRefreshToken = req.cookies.refreshToken;
// 리프레쉬 토큰 값이 있는지 확인, 없다면 에러 메시지.
if (!isRefreshToken) {
res.status(400).send({
data: null,
message: "refresh token not provided",
});
// 토큰이 유효한지 확인 후, 유효하지 않다면 에러 메시지 보냄.
} else if (isRefreshToken === "invalidtoken") {
res.status(400).send({
data: null,
message: "invalid refresh token, please log in again",
});
// 토큰이 유효한데 해독한 데이터가 db의 정보와 같은지 확인후, 아니라면 메시지 보냄.
} else {
const data = jwt.verify(isRefreshToken, process.env.REFRESH_SECRET);
if (!data) {
res.status(400).send({
data: null,
message: "refresh token has been tempered",
});
// 디비에 저장되어 있는 리프레쉬 토큰 정보와 쿠키에서 가져온 리프레쉬 토큰의 정보가 같다면 accessToken을 새로 생성해서 보내줘야 한다
} else {
// 아래와 같이 정보 가져옴
const payload = {
id: data.id,
userId: data.userId,
email: data.email,
createdAt: data.createdAt,
updatedAt: data.updatedAt,
};
// 다시 access 토큰 만들어서 전달
const accessToken = jwt.sign(payload, process.env.ACCESS_SECRET, {
expiresIn: "1d",
});
res.status(200).send({
data: {
accessToken: accessToken,
userInfo: payload,
},
message: "ok",
});
}
}
};
728x90
'프로그래밍 > 보안' 카테고리의 다른 글
HTTPS 프로토콜, 암호화 (0) | 2022.06.08 |
---|---|
IM-SPRINT-AUTH-TOKEN, JWT를 이용한 프로그램 구현. (client-token) (0) | 2022.06.08 |
OAuth 2.0이란? OAuth는 언제 왜 사용할까? (0) | 2022.06.08 |
mkcert라는 프로그램을 이용하여 로컬 환경에서 신뢰할 수 있는 인증서 만들어보기 - macOS (0) | 2022.06.08 |
토큰 기반 인증(Token-based Authentication) 그리고 JWT (Json Web Token) (0) | 2022.06.08 |
댓글