-
[Passport] isAuthenticate가 false를 반환할 때programing/Web 2019. 10. 3. 23:07
안녕하세요, Einere입니다.
(ADblock을 꺼주시면 감사하겠습니다.)
2019/09/06 - [programing/JavaScript] - [Express] cookie에 대하여
부스트캠프 미션 중, passport를 사용할 일이 있었습니다.
passport에서
req.isAuthenticate()
를 이용해 관리자 권한 인증 로직을 구현해야 했었습니다.module.exports = (req, res, next) => { console.log('[adminAuth.js]', req.isAuthenticated()); if (!req.isAuthenticated()) { res.status(401).end(); } else if (req.user.privilege > 1) { res.status(403).end(); } else { return next(); } };
대충 세션이 설정되어 있지 않으면 401을 쏴주고, 세션이 설정되어 있지만 권한이 2 이상인 경우엔 403을 쏴주는 로직입니다.
첫번째 오류 - 두번의 호출
그런데 특정 페이지에 접근하는 경우, 위의 "[adminAuth.js] ~~"가 두번 출력되고, 첫번째
req.isAuthenticate()
의 값은false
, 두번째 값은true
가 찍히는 현상을 발견했습니다.처음엔 단순히 두 번 호출되어서 제대로 작동하지 않는다고 생각했습니다.
The two calls actually serve distinct functions depending on what type of request is received and at what stage of authentication the flow is at.
그러나 Why is passport.authenticate called twice?에 따르면, 구글링을 하니 두 번 호출되는 것은 단순히 요청이 두번 왔기 때문이었습니다. 해당 글을 보고 프론트쪽 코드를 보니 다음과 같이 두번의 요청을 전송하고 있다는 것을 새삼 깨달았습니다...
created() { fetch(`${this.url}/admin/isPrivileged`, { method: 'GET', credentials: "include", }) .then(res => { if (res.status !== 200) throw "not privileged!"; return res.json(); }) .then(res => this.privilege = res.privilege) .catch(() => this.$router.push({name: 'normalHome'})); }, mounted() { fetch(`${this.url}/admin/users`, { method: 'GET', }) .then(res => { if (res.status !== 200 && res.status !== 304) throw "error in get all users!"; return res.json(); }) .then(res => { this.userList = res; }) .catch(err => console.log(err)); }
저는 프론트는 Vue.js를 사용했기 때문에, 라이프사이클 훅인 create에서 권한 정보를, mounted에서 유저 정보를 가져옵니다.
어찌됬건, 두번의 요청을 보내는 것은 오류가 아니라 정상적인 작동이었습니다..ㅎㅎ
참고로, static resource때문에 여러번 호출되는 경우도 있다고 합니다. 자세한 내용은 하단의 참조를 봐주세요.
두번째 오류 - isAuthenticated()의 반환값이 false
그러나 중대한 오류가 하나 더 있었습니다. 바로
req.isAuthenticate()
의 첫 번째 반환값이false
라는 것 이었습니다. 다른 페이지는 잘 작동하는데, 왜 유독 이 페이지(위의 vue코드에 해당하는 페이지)만 이렇게 작동하는지 몰랐습니다. 패스포트 도큐먼트와 구글링을 해도 답이 안나왔습니다. 그러다가, 아주 기적적으로 저의 하찮은 기억력을 탓하게 만드는 글을 보았습니다.It wasn’t a cors issue. Browser fetch wasn’t sending cookie to server, found answer here
Req.user undefined when calling backend api with passport-twitter auth에 따르면, 브라우저에서 서버로 부터 받은 쿠키를 요청 패킷에 안넣어 보내기 때문이라는 내용이 있었습니다. 즉, 서버로 부터 세션 정보를 담은 쿠키를 받았지만, 다음 요청에 해당 쿠키를 안넣어 요청을 보냈기 때문에 서버는 인증이 안 된 유저라고 판단해서 false를 뱉은 것이었습니다... 정말이지 클라-서버 통신 구현할때 수없이 많이 봐 온 문제인데, 또 까먹다니.. 정말 놀라운 기억력입니다. ㅠ
그래서 위 코드에 다음과 같이 credentials옵션을 추가했습니다.
created() { fetch(`${this.url}/admin/isPrivileged`, { method: 'GET', credentials: "include", }) .then(res => { if (res.status !== 200) throw "not privileged!"; return res.json(); }) .then(res => this.privilege = res.privilege) .catch(() => this.$router.push({name: 'normalHome'})); }, mounted() { fetch(`${this.url}/admin/users`, { method: 'GET', // 정말정말정말정말정말 중요한 부분입니다... credentials: "include", }) .then(res => { if (res.status !== 200 && res.status !== 304) throw "error in get all users!"; return res.json(); }) .then(res => { this.userList = res; }) .catch(err => console.log(err)); }
그랬더니 짜잔! 정상적으로 작동하네요.
여러분들은 이런 실수를 방지하기 위해, 래퍼 함수를 하나 만들어서 옵션 까먹지 않게 하세요..흑
참고
https://stackoverflow.com/questions/17498316/passportjs-middleware-being-called-multiple-times
'programing > Web' 카테고리의 다른 글
[NCloud] Naver NCloud로 Express서버 배포하기 - 2 (0) 2019.10.05 [NCloud] Naver NCloud로 Express서버 배포하기 - 1 (0) 2019.10.05 [Webpack] 웹팩에서 cass(scss) 적용하기 (0) 2019.09.19 [AWS] S3 버킷 삭제시 access denied 오류 해결 방법 (0) 2019.09.10 [AWS, Node] Elastic Beanstalk로 Express 앱 배포하기 (0) 2019.09.10 댓글