-
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
Documentation: Authenticate
Authenticate Authenticating requests is as simple as calling passport.authenticate() and specifying which strategy to employ. authenticate()'s function signature is standard Connect middleware, which makes it convenient to use as route middleware in Expres
www.passportjs.org
req.login()을 통해 로그인 처리를 하게 되면 req.session에 passport가 추가된다.req.login()을 통해 로그인 처리를 하게 되면 req에 user 객체를 정의한다.
req객체에 user객체가 추가 정의된다. 그리고 serializeUser로 인해 req.session에 passport.user가 추가된다.
passport객체의 user속성에는 테이블의 Primary Key가 들어간다. 이는 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
VSCode TS 디버깅 하는법
패스포트 authenticate()의 콜백을 커스텀하다가 문제가 생겨서 디버깅을 해야할 일이 생겼다. 그래서 VSCode로 TS 디버깅 하는 법을 찾아봤다. VSCode를 열자. 디버깅 탭을 클릭한다. 설정을 클릭한다. 그럼 선..
jamong-icetea.tistory.com
로그아웃은 다음과 같이 작업했다.
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
Express 오류 처리
오류 처리 다른 미들웨어 함수와 동일반 방법으로 오류 처리 미들웨어 함수를 정의할 수 있지만, 오류 처리 함수는 3개가 아닌 4개의 인수, 즉 (err, req, res, next)를 갖는다는 점이 다릅니다. 예를 들면 다음과 같습니다. app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send('Something broke!'); }); 오류 처리 미들웨어는
expressjs.com
'개발일지' 카테고리의 다른 글
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