게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌11 - NodeJS - 8년 전 등록 / 7년 전 수정

Passport로 Facebook 로그인

안녕하세요. 이번 시간에는 passport를 사용해 facebook 아이디로 로그인을 구현해보겠습니다. 이것을 응용하면 google이나 twitter, kakao 등 passport를 지원하는 SNS 아이디로 로그인할 수 있습니다.

우선 passport-facebook을 설치합니다.

npm install --save passport-facebook

설치가 완료되었으면 페이스북에 로그인 요청을 보낼 라우터를 추가합니다.

route.js

... // 이전 시간 코드에서 계속
router.get('/auth/facebook', passport.authenticate('facebook', {
  authType: 'rerequest', scope: ['public_profile', 'email']
}));
router.get('/auth/facebook/callback', passport.authenticate('facebook', { failureRedirect: '/' }), function(req, res) {
  res.redirect('/');
});

전 시간과 달리 router에 두 개를 추가했습니다. /auth/facebook은 로그인 요청을 할 링크입니다. 이 링크를 html로 만들고 클릭하면 passport를 통해 페이스북으로 로그인 요청이 전송됩니다. authenticate 메소드 뒤의 facebook은 사용할 전략의 이름을 적어주면 됩니다.

authType: 'rerequest'는 매번 로그인 할 때마다 뒤의 public_profile과 email을 달라고 요청하는 겁니다. 이것을 해둬야 실수로 사용자가 요청을 거절했을 때 다음 로그인 시 다시 얻어올 수 있습니다. 뒤에 scope는 페이스북에 사용자에 대한 정보로 무엇을 요청할 지 정하는 부분입니다. 친구목록이나 좋아요한 페이지 등등 다양한 정보를 얻어올 수 있습니다.

/auth/facebook/callback은 페이스북이 검증을 마치고 난 결과를 전송해주는 주소입니다. 여기로 전송한 정보를 처리하는 코드를 만들어보죠. 지난 시간 만들었던 passport.js의 LocalStrategy 아래에 다음 코드를 추가해줍니다.

passport.js

const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const FacebookStrategy = require('passport-facebook').Strategy; // 이 부분 추가
const Users = require('./user');

module.exports = () => {
  ... // 이전 시간 코드에서 계속
  passport.use(new FacebookStrategy({
    clientID: '페이스북 클라이언트 아이디',
    clientSecret: '페이스북 클라이언트 시크릿',
    callbackURL: '홈페이지주소/auth/facebook/callback',
    passReqToCallback: true,
  }, (req, accessToken, refreshToken, profile, done) => {
    User.findOne({ id: profile.id }, (err, user) => {
      if (user) {
        return done(err, user);
      } // 회원 정보가 있으면 로그인
      const newUser = new User({ // 없으면 회원 생성
        id: profile.id
      });
      newUser.save((user) => {
        return done(null, user); // 새로운 회원 생성 후 로그인
      });
    });
  });
};

슬슬 코드가 콜백 지옥으로 빠져들어가고 있네요. 찬찬히 살펴봅시다. 일단 passport-facebook도 Strategy를 사용합니다. 전략이라고 했죠? 페이스북 로그인은 페이스북 서버에서 clientID, clientSecret, callbackURL을 검사합니다. 이 부분은 나중에 무엇을 넣어야하는지 알려드릴게요.

passReqToCallback 옵션은 지난 시간에 설명드렸습니다. 뒤의 콜백 함수에 req 매개변수를 추가해주죠.

accessToken, refreshToken은 페이스북 API를 사용할 수 있는 토큰을 전달해줍니다. 만약 페이스북이 토큰 내놔라! 라고 하면 이 토큰을 주면 됩니다. profile은 간단한 페이스북 사용자의 정보를 알려줍니다. 별로 알려주는 게 많이 없어서 추가적인 정보를 원한다면 추가 API를 호출해야 합니다.

이제 전략 부분을 설명하겠습니다. 일단 profile.id로 이미 우리 사이트의 회원인가를 조회해봅니다. 만약 우리 사이트에 이미 가입되어 있으면 done(err, user)로 바로 로그인합니다. 회원이 아니라면 새로 회원가입하는 거죠.

거의 다 되었는데 이제 clientIDclientSecret을 넣어야합니다. 이것이 있어야 페이스북에서 보내준 결과가 올바른 사이트에 전달되었는지 확인할 수 있거든요. 이것을 얻으려면 페이스북 개발자 홈페이지에 접속해야 합니다.

로그인 후 상단 오른쪽 내 앱 -> 새 앱 추가 -> 웹사이트를 누르세요. 원하는 앱 이름을 적고 Create New Facebook App ID를 누르면 됩니다.

undefined

저는 test로 앱을 만들었는 데 이름은 원하는 걸로 바꾸세요. 정보를 알맞게 적고 앱 ID 만들기를 누릅니다. 사이트 주소도 넣어줍니다.

undefined

이제 오른쪽 위 내 앱 -> test에 가면 clientID와 clientSecret을 확인할 수 있습니다.

undefined

마지막으로 좌측 메뉴에서 제품 -> 제품 추가를 클릭하여 Facebook 로그인 제품을 활성화합니다. 웹을 클릭한 후 사이트 주소를 입력하면 됩니다. 나머지 것들은 건너뛰어도 됩니다.

좌측 메뉴에 Facebook 로그인이 추가되었는지를 확인합니다.

undefined

위의 코드를 활용해서 다른 SNS 로그인도 구현해보세요. 저는 현재 페이스북, 구글+, 트위터, 카카오, 네이버 이렇게 다섯 개를 사용중입니다. 다음 시간에는 socket.io에 대해 알아보겠습니다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

11개의 댓글이 있습니다.
3년 전
제로초님 passport 예제를 보고 많이 도움이 되었습니다.

근데 한 가지 궁금한 점이 있는데

제가 연동 해제 기능을 해보려고 해서 passport에서 받아온 token이나 id값을

session에 저장 후 연동 해제 버튼을 클릭 시 서버단에서 해제를 하려고 합니다.

근데 no authentication key 라는 에러 메세지가 나오고 되지 않습니다..

혹시 passport에서 받은 값들이 후에 사용 될 때 유효하지 않는 값이 되어버리는 건가요?
4년 전
책을 보면서 예제를 따라해 보고 있습니다.
다음 계정 로그인 기능을 구현하고 로컬이 아닌 실제 윈도우 서버에
서비스를 올리고 주소가 www.abc.com:8001 같은 포트 노출을 막기 위해
URL 재작성 기능을 사용하여 역방향 프록시를 설정하였습니다.

포트 번호를 입력하고 접속해서 카카오 로그인 기능을 사용하면 정상 동작하는데
역방향 프록시 기능을 사용하여 포트 번호 없이 접속하면 404 에러가 발생합니다.

개발자 도구로 내용을 살펴 보니 역방향 프록시로 서비스할 때는 요청 주소가
아래와 같이 잘못 보내지고 있습니다.

포트 번호 사용 시
https://kauth.kakao.com/oauth/authorize?response_type=code&redirect_uri=http%3A%2F%2Fwww.bado.co.kr%3A52273%2Fauth%2Fkakao%2Fcallback&client_id=

포트 번호 없이(역방향 프록시)
http://www.bado.co.kr/oauth/authorize?response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A52273%2Fauth%2Fkakao%2Fcallback&client_id=

혹시 어떤 부분이 문제인지 도움 주실수 있는지요?
확인 부탁드립니다.
4년 전
역방향 프록시 설정이 잘못된것으로 보입니다. 또한 redirect_uri에 52273 포트가 들어있는데 카카오 앱에서 Redirect URI로 52273 포트를 쓴 주소를 넣으셨나요?
4년 전
포트 사용한 주소와 포트를 사용하지 않은 주소를 모두 넣었습니다. 역방향 프록시 설정이라고 해도 80 포트로 들어온 요청을 52273 포트를 사용하는 내부 ip로 바꿔주는 것 밖에 없는 간단한 내용인데요. 간단한 것도 쉽지가 않네요. 답변 감사합니다.
4년 전
해당 facebook 예시처럼 passport로 다른 소셜 인증을 구현하려고 하는데, has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. 에러로 몇일 동안 삽질 하고 있습니다. 물론 localhost 가 아닌 도메인이나 ip로도 테스트 하고 있는데, 같은 문제로 직면하고 있네요.. 기본적으로 express에서 cors({origin: true}) 이 옵션을 주고 사용 중입니다. ㅠㅠ 추가적인 설정이 필요한 부분이 있을까요..?? front 에서는 단순 get 호출을 해주고 있습니다. (port 가 달라서 생긴 문제 같네요..^^:;)
4년 전
프론트에서 get ajax 요청을 보내신다는 말씀이신가요? passport facebook은 ajax로 하시면 안 됩니다. a 태그로 해야합니다.
4년 전
React 에서 로그인 버튼 클릭후, 팝업창이 열리고, 확인이 완료되면 Callback url타고 서바단에서 완료 까지 만들었습니다. 그 이후, 팝업창은 어떻게 닫고, 완료처리를 할 수 있을까요..? redirect 로 원하는 이동 경로를 주면 팝업창이 해당 경로로 이동을 합니다..ㅠㅠ
4년 전
팝업창은 window.close()로 닫을 수 있습니다. 또한 팝업창에서 부모 창을 자바스크립트로 접글할 수 있어, 접근한 다음에 부모창을 다른 주소로 location.href 등으로 이동해주시면 됩니다.
4년 전
와.. 소셜로그인 연동하는데 무지 고생했는데 제로초님이 말씀하신 부분적으로 서버사이드 렌더링을 적용하는 방법을 못찾다가 드디어 발견했네요ㅠㅠ 넌적스 같은거 안쓰시고 리액트 하시는 분들은 redirect할때 클라이언트URL로 해보세요!
4년 전
안녕하세요. 잘 봤습니다. 인증 후에 accesstoken을 받을 수 있는데 token을 브라우저 LocalStorage에 저장하고 싶은데 어떻게 하는게 좋을까요
4년 전
done(null, user)의 user 객체에 토큰을 추가해서 res.json(user)로 프론트로 보내면 받아서 쓰실 수 있습니다.
6년 전
저는 react native로 앱을 만들고 있습니다. 그래서 session의 토큰 저장이 아닌 jwt를 해야하는데 passport로 소셜 로그인을 할려면 어찌 해야할까요...?
6년 전
jwt용 패스포트 모듈들이 있습니다. npm에서 찾아보세요.
6년 전
감사합니당
7년 전
" 클라이언트 로딩 후 직접 서버 세션 조회를 해야 합니다.
친절하고 빠른 답변, 감사합니다 며칠 생각 안나던 문제가 해결되듯 답답함이 풀리네요!

혹시 저와 같이 Vue-cli나 React에서 고민을 하시는 분들이 있을까봐 간단하게 남겨둡니다
- vue는 https://www.npmjs.com/package/vue-session 해당 모듈 사용해서 session키를 저장하면 서버사이드 렌더링 없어도 가능할듯 보입니다.
7년 전
안녕하세요 ㅎㅎ 항상 글 잘보고있습니다 이번에도 좋은글 써주셔서 감사합니다
다름이 아니라 passport를 vue프로젝트와 연동 시키려고 하는데요 프로그래밍 기획과정에서 약간의 질문이 생겨서 이렇게 글을 남기게 되었습니다.

passport는 세션스토리지 형식으로 저장하는걸로 알고있습니다 그래서 질문이 생겼는데요
Vue의 컴포넌트 형식의 개발방식이나 ReactJs의 jsx의 클래스를 사용한 앱과같은 웹개발..을 보면서 느끼는건데 여기서 passport를 붙이려면 어떤식으로 생각하면 좋을까요?

Vue는 -cli를 사용해서 빌드를 하면 빌드 파일이 생기고 정적으로 파일을 제공하는 것으로 알고있습니다. 그래서 서버와의 통신을 htttp.get or http.Post 형식으로 주고받는데요 이 과정 만으로도 사용자의 피씨의 정보를 받아 세션화 시켜서 저장이 가능 한지가 궁금하네요

전통적인 웹 개발방식에서 벗어나 새로운 방식을 사용하고자 하는데 기존에 생각하던 방식이랑 전혀다르다보니 이렇게 질문하게 되었습니다.
7년 전
서버 사이드 렌더링을 사용해야 합니다. 제 블로그도 리액트인데 세션이 유지되는 이유가 서버사이드렌더링을 하여 처음 렌더링할때부터 세션 정보를 삽입하기 때문입니다. 만약 서버사이드렌더링이 불가능하다면 클라이언트 로딩 후 직접 서버 세션 조회를 해야 합니다.
7년 전
중간에 passport.js에 25line })); 인듯 한데요~
7년 전
감사합니다 ㅎㅎ
7년 전
게시물이 구글을 다 뒤진 것보다 더 도움이 되었습니다! 그런데 몇 가지만 질문 드리고 싶은데요~ 맨 처음에 클라이언트가 서버에게 /auth/facebook으로 요청을 보낼 때 어떤 정보를 보내는 건가요?? 그리구 마지막에 done이 호출되는데, 이제 로그인이 끝나고 클라이언트가 서버에게 요청을 할 때는 facebook access_token이 전송되는건가요?? 워낙 자료 찾기가 어려워서 지식이 부족하네요 ㅜㅜ 죄송합니다
7년 전
/auth/facebook으로 보내는 건 서버에게 passport 요청을 수행하라고 지시하는 것이고요. 서버에서 한 번 더 facebook 인증 서버로 요청을 합니다. facebook 인증 서버에서 프로필과 액세스 토큰을 돌려주면 지정해둔 passport 전략이 실행되고요. DB에 저장 후 done이 호출되면 req.user에 profile이 저장되는 겁니다. access_token은 여기서 아무 역할이 없습니다.