본문 바로가기
Back-End Frameworks/Node.js

19)Nodejs_간이 SNS 서비스 만들기_(3) passport 모듈로 로그인 구현

by Downy_J 2023. 7. 24.
728x90
반응형
SMALL

로그인.. 보안이 중요한 부분임

직접 구현 할 수도 있으나 세션과 쿠키처리등

복잡함 좀.

해서 검증된 모듈을 쓸 필요가 있음

 

PassPort 를 쓰는것!

 

근데 이게 뭔데?

요즘 SNS로그인도 하는데? 카카오나 구글 네이버 페북 등 

기존 있는걸로도 로그인 되잖음?

 

ㅇㅇ 그런것도 이

설치 하면 준비 끝!


Passport 모듈 만들고 연결까지
app.js
require('./passpoprt') = require('./passpoprt/index.js') 다
(폴더 내 index.js 일시 생략 가능)
passport.initialize() 미들웨어는 요청(req 객체)에 passport 설정을 심고,
passport.session() 미들웨어는 req.session 객체에 passport 정보를 저장.

여기서 req.session 객체는 express-session에서 생성하므로
passport 미들웨어는 express-session 미들웨어보다는 뒤에 위치해 연결 해야 함.

passport/index.js
이렇게 파일명을 만들었으니 passport 폴더 안에
local과  kakao 만들어주고
중요한건 저 둘임.

serializeUser로그인시 실행. 
req.session(세션) 객체에 어떤 데이터를 저장 할지 정하는 메서드

매개 변수로 user 받고 done 함수에 두번째 인수로 user.id를 넘긴다.

done 첫번째 인수는 에러 뜨면 쓰는곳, 두번째 인수는 저장하고싶은 데이터 넣는곳.
근데 왜 user.id 만 저정함?
세션에 유저정보 모두 저장하면 세션 용량이 커지며 데이터 일관성의 문제땜에 사용자id 만 저장하라고 한것
----------------------------------------------------------------------------------
deserializeUser은 매 요청시 실행됨.
passport.session 미들웨어가 이 메서드를 호출
serializeUser의 done의 두번째 인수로 넣은  user.id가
deserializeUser의 매개변수가 됨.(여기선 user.id다)

세션에 저장한 user.id 받아 DB에서 유저정보 조회
조회한 정보를 req.user에 저장하고 앞으로 req.user를 통해 로그인한 유저 정보를 가져올수 있음

  • serializeUser : 유저 정보 객체를 세션에 아이디로 저장하는 것.
  • deserializeUser : 세션에 저장한 아이디를 통해 유저 정보 객체를 불러오는 것.

세션에 불필요한 데이터는 담지 않기위해서 이렇게 한다.

 


전체 과정

  1. router 통해 login 요청이 들어옴
  2. router에서 passport.authenticate 메서드 호출
  3. login 전략 수행
  4. login 성공 => 유저 정보 객체와 함께 req.login 호출
  5. req.login 메서드가 passport.serializeUser 호출
  6. req.session에 유저 아이디만 저장
  7. 로그인 완료!!

[ 로그인 후 ]

  1. 요청 들어옴
  2. router 요청이 도달전 passport.session 미들웨어가 passport.deserializeUser 메서드 호출
  3. req.session에 저장된 id로 데이터베이스에서 유저 조회
  4. 조회된 유저 정보를 req.user에 저장
  5. 라우터에서 req.user객체 사용 가능

각각 로컬 로그인과 카카오 로그인의

로그인 과정을 어떻게 처리 할건지

설명하는 파일임


local 로그인 구현

타 SNS 서비스 안타고 자체적으로 회원가입 후 로그인 하는 기능

아이디/비번, 이멜/비번 등을 통해 로그인 하는것을 말함

 

passport에서 구현 할라믄 passport-local 모듈이 필요함.

이제 어떻게 구현 할건지 빌드업만 하믄됨.

 

먼저 만들건 회원가입, 로그인, 로그아웃 이다

이런 라우터는 접근 조건이 있음.

로그인한 유저회원가입과 로그인 라우터엔 접근하면 안됨! 마찬가지로

로그인 안한 유저로그아웃 라우터엔 접근하면 안됨!

결론, 접근 권한 제어모듈이 필요

middlewares/index.js
Passport는 req 객체에 isAuthenticated 메서드를 추가함
그럼 이 req.isAuthenticated() 가 true거나 아니면  false로 403을 던질거임
비슷한 개념이것제..?

이렇게 2개의 미들웨어를 만들었음.


회원가입 라우터나 로그인 라우터는

로그인안한 사람만 접근 되야 함

이럴때 라우터에 로그인 여부 검사하는 미들웨어를 넣어 

걸러낼 수있다

routers.page.js
미들웨어 있는 파일 경로 불러오고
res.locals.user  속성에 req.user로 한 이유?

Nunjucks에서 이 user객체를 통해 사용자 정보에 접근 할 수 있게 됬었음.
만들어 불러온 컨트롤러 연결만 해주면 된다.
이렇게 까지 나누는 이유는 아마 어디 문제가 생겼을시
좀 더 빠르고 쉽게 고치기 위함이 아닌듯 함.

회원가입, 로그인, 로그아웃 라우터 만들기...전 컨트롤러 부터 만들자

controller/auth.js

암호화 해주는 모듈
그리고 설치했던 패스포트
그리고 유저 모델을
이 컨트롤러에 불러온다
회원가입 컨트롤러다
기존 같은 이메일로 가입한 사용자 있는 먼저 조회
있다면 회원가입페이지로 되돌려보냄
(주소 뒤에 에러를 쿼리스트링으로 표시)

같은 이멜 쓴사람 없으면 비번 암호화 하고
유저 정보 생성
(가입시 비번은 암호화 해서 저장 해야함 - bcrypt 모듈을 씀.)
bcrypt의 hash 메서드 쓰면 쉽게 암호화 가능
두번째 인수 부분은 반복횟수와 비슷한 기능임
(12 ~ 31 까지)

로그인 컨트롤러다
로그인 요청이 들어올 시 passport.authenticate('local') 미들웨어가 로컬 로그인을 수행함.
(미들웨어인데 라우터 미들웨어 안에 있음..)
미들웨어에사용자 정의 기능을 추가하고싶을때 이렇게 하면됨.
이때는 내부 미들웨어에 (req, res, next)를 인수로 제공해서 호출하면됨.
로그아웃 컨트롤러다
메인페이지로 리다이렉트만 해준다
routes/auth.js

 

회원가입 라우터
에다 아까 만든 컨트롤러를 불럴와 연결
로그인 라우터
에다 아까 만든 컨트롤러를 불럴와 연결
로그아웃 라우터
에다 아까 만든 컨트롤러를 불럴와 연결

카카오는 인증방식이 자체적으로 있기때문에
이렇게만 연결한다.

passport/localStrategy.js

로그인 동작(전략)을 구현 했음...
passport-local 모듈에서 Strategy 생성자를 불러와 그 안에
전략을 구현
LocalStrategy 생성자의 첫번째 인수 : 주어진 전략에 관한 설정을 하는곳
usernameField, passwordField 에 일치하는 로그인 라우터의
req.body 속성명을 적으면 됨.
req.body.email엔 이멜주소,
req.body.password엔 비번이 담겨 들어오므로
email, password 라고 각각 넣는다
실 전략 수행 async함수

LocalStrategy 생성자 두번째 인수로 들어감.
첫번째 인수로 넣어준 email과 password는 각각 async 함수의 첫번째와 두번째의 매개변수가 됨.

세번째 매개변수인 done 함수는 passport.authenticate의 콜백 함수임


[전략의 내용]
1. 유저 DB에서 일치하는 이메일 있나 찾아봄.
2. 있으면 bcrypt의 compare 함수로 비번 비교
3. 비번까지 일치해? 그럼 done 함수의 두번째 인수로 유저정보 보냄

dnone의
두번째 인수를 사용하지 않는경우는 로그인 실패했을때 뿐임
첫번째 인수를 사용하는건 서버쪽 에러가 났을때
세번째 인수를 사용하는건 로그인 처리 과정에서 비번이 불일치하거나 회원이 아닌 경우 뜨는 에러

이렇게 done이 호출 후 다시 passport.authenticate의 콜백 함수에 나머지 로직이 실행
로그인 성공했다믄 메인 페이지로 리다이렉트
로그인 form 대신 회원정보 form이 뜬다

카카오 로그인 구현

sns 로그인 구현은 다른 구글 네이버 페북등 비슷... 비슷(?) 하다

장점은 로그인 인증관련 그 과정들을 맡겨 버리는것.

내가 뭘 따로 보안이니 뭐니 신경쓸 필요 없다

passport/kakaoStrategy.js
pasport-kakao 모듈로 부터 Strategy 생성자를 불러와 전략을 구현

카카오 로그인에 대한 설정.
clientID는 카카오에서 발급해주는 아이디
노출되면 안되기때문에 process.env.KAKAO_ID 로 설정
(나중에 발급 받으면 .env에 넣을거)
callbackURL은 카카오로부터 인증결과를 받을 라우터 주소

아래 라우터 작성시 이 주소를 쓸거
기존 카카오를 통한 회원가입한 유저가 있는지 조회
있으면 회원가입 필요 없으므로 유저정보와 함께
done 함수 호출
카카오를 통해 회원가입한 유저가 없다면 회원가입을 진행

카카오 인증 후 callbackURL에 적힌 주소로
accessToken, refreshToken과 profile을 보냄.
그럼 profile에는 유저 정보가 들어있음

(카카오에서 보내주는것이기에 데이터는 콘솔로그로 확인 해봐야함.)

profile 객체에서 원하는 정보를 꺼내와 회원가입을 하면됨
유서 생성한 뒤 done 함수를 호출

카카오 로그인 라우터 만들기

routes/auth.js
GET /auth/kakao로 접근하면 카카오 로그인 과정이 시작됨

layout.html의 카카오 버튼에 

가 붙어 있음.
저 GET /auth/kakao 에서 로그인 전략을 수행 하는데
처음엔 카카오 로그인 창으로 리다이렉트함

그 창에서 로그인 후 성공 여부를 GET /auth/kakao/callback으로 받음

이 라우터는 카카오 로그인 전략을 다시 수행함

로컬 로그인과 다른점 : passport.authenticate 메서드에 콜백 함수를 제공하지 않음.

카카오 로그인은 로그인 성공시 내부적으로 req.login을 호출.

콜백 함수 대신 로그인 성공시 어디로 이동할지를 failureRedirect속성에 적고,  성공시에도 어디로 이동할지 다음 미들웨어를 이어줘야함

추가한 auth 라우터를 app.js에 연결

app.js

auth 라우트 경로 지정하고
/auth인 카카오 로그인 미들웨어 주소 연결

끝!

... 이 아니라 

https://developers.kakao.com/

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

여기 가서 아까 못했던거

clientID 발급 받아야함..

728x90