인증 미들웨어 설정 및 적용
인증이 필요한 api로 접근시 토큰 정보가 있고 유효한지를 먼저 체크하는 미들웨어를 생성한다.
http 헤더에 authorization 키가 있는지 체크하고 있다면 토큰 정보가 Bearer 다음에 토큰 정보가 들어가 있으므로 Bearer 가 잇는지 체크하고 없다면 401 에러를 리턴한다.
토큰을 꺼내서 verify 함수를 사용해서 토큰이 유효한지 체크한다. 체크후에는 req에 userId와 roles 정보를 세팅하여 뒤에 나올 권한 미들웨어에 넘겨준다.
src/middleware/AuthMiddleware.ts
import {verify} from 'jsonwebtoken';
export class AuthMiddleware {
static verifyToken = async (req, res, next) => {
if (!req.headers["authorization"] || !req.headers["authorization"].startsWith("Bearer ")) {
return res.status(401).send({
message: "Unauthorized!"
});
}
const token = req.headers["authorization"].substring(7);
verify(token, process.env.secret, (err, decoded) => {
console.log(err);
if (err) {
return res.status(401).send({
message: "Unauthorized!"
});
}
console.log(decoded);
req.userId = decoded.jti;
req.roles = decoded.roles;
next();
});
}
}
인증이 필요한 api에 인증 미들웨어를 적용한다.
로그인과 회원가입인 /auth에는 인증이 필요없고 /images에도 인증이 없게 설정한다. 앞에서 만든 admin 사이트에에 인증 미들웨어를 아래와 같이 설정한다.
src/router/index.ts
import {Router} from "express";
import image from "./image";
import auth from "./auth";
import admin from "./admin";
import {AuthMiddleware} from "../middleware/AuthMiddleware";
import board from "./board";
import comment from "./comment";
const routes = Router();
routes.use('/board', board);
routes.use('/image', image);
routes.use('/comment', comment);
routes.use('/auth', auth);
routes.use('/admin', AuthMiddleware.verifyToken, admin);
export default routes;
게시판의 경우는 쓰기, 수정, 삭제 시에 인증이 필요하므로 아래와 같이 인증 미들웨어를 설정한다.
src/router/board.ts
import {Router} from "express";
import {BoardController} from "../controller/BoardController";
import {AuthMiddleware} from "../middleware/AuthMiddleware";
const routes = Router();
routes.post('', AuthMiddleware.verifyToken, BoardController.addBoard);
routes.get('/list', BoardController.findAllBoard);
routes.get('/count', BoardController.countBoard);
// routes.get(/^\/(\d+)$/, BoardController.findOneBoard);
routes.get('/:id', BoardController.findOneBoard);
routes.put('', AuthMiddleware.verifyToken, BoardController.modifyBoard);
routes.delete('', AuthMiddleware.verifyToken, BoardController.removeBoard);
export default routes;
댓글의 경우도 쓰기, 수정, 삭제 시에 인증 미들웨어를 적용한다.
import {Router} from "express";
import {CommentController} from "../controller/CommentController";
import {AuthMiddleware} from "../middleware/AuthMiddleware";
const routes = Router();
routes.post('', AuthMiddleware.verifyToken, CommentController.addComment);
routes.get('/list', CommentController.findAllComment);
routes.get('', CommentController.findOneComment);
routes.put('', AuthMiddleware.verifyToken, CommentController.modifyComment);
routes.delete('', AuthMiddleware.verifyToken, CommentController.removeComment);
export default routes;
권한 미들웨어 적용
권한이 필요한 api에 인증 미들웨어를 적용하기 위해서 권한 미들웨어를 생성한다.
인증 미들웨어가 먼저 적용되고 인증 미들웨어에서 req에 userId와 roles가 설정되어서 들어오기 때문에,
/api/admin으로 들어올때 req.roles에 ROLE_ADMIN 이 있는지 체크하고 없으면 권한 없음 에러를 리턴한다.
src/middleware/AuthMiddleware.ts
export class AuthMiddleware {
...
static hasRole = async (req, res, next) => {
console.log(req.userId, req.roles);
if (req.baseUrl.startsWith('/api/admin')) {
if (req.roles.indexOf('ROLE_ADMIN') < 0) {
return res.status(401).send({
message: "Admin Role is needed!"
});
}
} else if (req.url.startsWith('/api/moderator')) {
if (req.roles.indexOf('ROLE_MODERATOR') < 0) {
return res.status(401).send({
message: "Moderator Role is needed!"
});
}
}
next();
}
}
admin api에 권한 미들웨어를 적용한다.
src/router/index.ts
...
routes.use('/admin', AuthMiddleware.verifyToken, AuthMiddleware.hasRole, admin);
export default routes;