-
2019-09-20 개발일지개발일지 2019. 9. 20. 17:15
오늘은 수정사항 반영과 개인 학습으로 패스포트를 이용하여 로그인 로그아웃, 에러 핸들러를 만들었다.
[수정 사항 리스트]
- 게임 가이드 목록 화면 페이지당 게시글 수를 10개에서 20개로 수정
패스포트를 이용하여 로그인 로그아웃을 만들어봤다.
예전에 학습해서 블로그에 포스팅했을 때는 모듈화를 하지 않고 app.js에서 모두 처리했었는데, 이번엔 TS + 모듈화 환경에서 작업해봤다.
어제 개발일지에서 작성한 코드를 기반으로 수정했다.
passport.ts
import User from 'models/userModel'; import passport = require('passport'); export default (passport: passport.PassportStatic) => { ... passport.deserializeUser(async (id: number, done) => { try { const findOption = { where: { id } }; const user = await User.findOne(findOption); if (user) { return done(null, user.get()); } return done(null, false); } catch (e) { return done(e); } }); };
serializeUser()에는 변동이 없고, deserializeUser()만 변동이 있다.
기존에는 return done(null, user)로 작성했었는데 user에서 get()메소드를 사용해서 객체를 반환했다.
그냥 user를 반환해버리니까 sequelize 인스턴스가 반환되더라.
local-strategy.ts
import User from 'models/userModel'; import { Strategy as LocalStrategy } from 'passport-local'; import CustomError from 'error/customError'; import { PassportStatic } from 'passport'; export default (passport: PassportStatic) => { passport.use(new LocalStrategy(async (username: string, password: string, done) => { try { ... const user = await User.findOne(findOption); if (user) { if (user.getDataValue('userPw') !== password) { throw new CustomError(10004); } return done(null, user.get()); } return done(null, false); } catch (e) { return done(e); } })); };
해당 코드도 별로 바뀐게 없는데, 이전에 where에 username과 password 모두 넣어 데이터를 찾았는데 이번엔 에러 구문을 알려주기 위해 username으로만 찾은 후에 패스워드가 동일한지 코드상에서 비교하도록 수정했다.
그리고 역시 done()에서 sequelize 인스턴스가 아닌 user객체를 반환했다.
authRoute.ts
import express from 'express'; import { PassportStatic } from 'passport'; import * as authController from 'controllers/authController'; export default (app: express.Application, passport: PassportStatic) => { app.post('/login', authController.login); };
기존 passport.authenticate()로 연결하던 걸 authController의 login을 타도록 수정했다.
authController.ts
import express, { NextFunction } from 'express'; import passport from 'passport'; import User from 'models/userModel'; import CustomError from 'error/customError'; /** * 로그인 * @author Johnny * @param req.session.passport.user 로그인 사용자 고유 번호 * @param req.body.userId 사용자 아이디 * @param req.body.userPw 사용자 패스워드 */ export function login( req: express.Request, res: express.Response, next: NextFunction ) { if (req.session && req.session.passport && req.session.passport.user) { throw new CustomError(10002); } const { userId, userPw } = req.body; if (!userId || userId.length <= 0 || !userPw || userPw.length <= 0) { throw new CustomError(10201); } passport.authenticate('local', (err: Error, user: User) => { if (err) { return next(err); } if (!user) { throw new CustomError(10003); } req.login(user, err => { return err ? next(err) : res.status(200).json({ message: '로그인 성공' }); }); })(req, res, next); }
어제 라우트에서 작업했던 authenticate()보다 뭔가 좀 길어졌다.
콜백을 커스텀했기 때문이다.
Custom Callback 참고: http://www.passportjs.org/docs/authenticate
req.login()을 통해 로그인 처리를 하게 되면 req.session에 passport가 추가된다.req.login()을 통해 로그인 처리를 하게 되면 req에 user 객체를 정의한다.
그리고 serializeUser로 인해 req.session에 passport.user가 추가된다.
이는 serializeUser()에서 done(null, user.id)로 id를 저장하기 때문이다.
이후 deserializeUser()가 호출될 때 마다 (라우트 이동이라던가) req.session.passport.user의 값을 확인하고 DB를 조회하여 존재하는지 판단하여 유효성을 검사한다.
참고로 authenticate()이후에 (req, res, next)를 적어주지 않으면 authenticate()가 실행되지 않으니 주의.
요거 때문에 VSCode로 TS 디버깅을 했다...;
VSCode TS 디버깅 하는법: https://jamong-icetea.tistory.com/300
로그아웃은 다음과 같이 작업했다.
authRoute.ts
export default (app: express.Application, passport: PassportStatic) => { ... app.get('logout', authController.logout); };
authController.ts
export function logout( req: express.Request, res: express.Response, next: NextFunction ) { if (req.session && req.session.passport && req.session.passport.user) { req.logout(); return res.status(200).json({ message: '로그아웃 되었습니다.' }); } throw new CustomError(10001); }
그리고 에러 핸들러를 커스텀해봤다.
customErrorHandler.ts
import CustomError from 'error/customError'; import express, { NextFunction } from 'express'; export default ( err: CustomError, req: express.Request, res: express.Response, next: NextFunction ) => { if (err instanceof CustomError) { return res.status(500).json({ error: err }); } next(err); };
이렇게 만들고 express_config.ts에서 app.use(CustomErrorHandler)로 미들웨어 등록을 해줬다.
참고: https://expressjs.com/ko/guide/error-handling.html
'개발일지' 카테고리의 다른 글
2019-09-24 개발일지 (0) 2019.09.24 2019-09-23 개발일지 (0) 2019.09.23 2019-09-19 개발일지 (0) 2019.09.19 2019-09-18 개발일지 (0) 2019.09.18 2019-09-17 개발일지 (0) 2019.09.17