honey_pot
[Node.js] Passport를 이용한 Google OAuth 로그인 구현 본문
http://www.passportjs.org/packages/passport-google-oauth20/
✨ 설치 ✨
passport-google-oauth20 을 설치한다.
$ npm install passport-google-oauth20
✨ 사용법 ✨
Google 클라우드 플랫폼 (https://console.cloud.google.com/apis) 에서 프로젝트를 생성한다.
포도알 세개 배너 - 새프로젝트
프로젝트 이름을 설정한다.
1️⃣ OAuth 동의 화면 구성
생성된 프로젝트의 서비스단에서 OAuth 동의 화면을 먼저 설정한다.
google workspace 사용자가 아니면 외부 type만 설정 가능하다.
앱 이름을 작성하고 이메일은 default가 지금 로그인한 계정이다.
앱 로고는 authencation을 요청할 때 뜨는 창에 보이는 로고를 의미한다. 없어도 된다.
도메인 없이 node.js에 구글 OAuth 테스트만 할 것이므로 도메인 부분은 비운다.
하단의 개발자 이메일도 적고 다음으로 넘어간다.
범위 추가 또는 삭제 - API 리스트 중에서 구글 계정에 요청할 정보를 선택한다.
여기서 선택한 API는 email, profile, openid이다.
저장 후 계속 클릭
테스트를 통해 테스트 사용자만 액세스하게 할거라면 작성하지만 난 안 할 것이므로 빈칸
저장 후 계속 클릭
여기까지 동의 화면 구성은 끝이다.
2️⃣ OAuth 클라이언트 ID 생성
사용자 인증 정보 - +사용자 인증 정보 만들기 - OAuth 클라이언트 ID
애플리케이션 유형에서 웹 애플리케이션을 선택하고 이름을 작성한다.
app.js 에서 연결한 port가 3000이므로 http://localhost:3000에서 브라우저로 요청이 간다.
승인된 자바스립트 원본 URI에 http://localhost:3000 을 입력한다.
구글 authentication이 끝나고 사용자가 이동하게 될 주소이다.
/auth/google/secrets 로 이동하게 만들었다.
다 적었으면 만들기 클릭
생성됨 창이 뜨며
클라이언트 ID (client ID)와
클라이언트 비밀번호(client secret) 가 뜨면 OAuth 설정은 끝이다.
.env 파일에 클라이언트 ID와 비밀번호를 입력한다.
app.js 맨위에 추가
✔ const GoogleStrategy = require('passport-google-oauth20').Strategy;
.env에 적은 ID와 SECRET 을 대입하고 URL은 승인된 리디렉션 URI 을 적는다.
구글이 API 정책을 바꾸면서 Google Plus APIs 를 삭제한 이후,
사용자에게 migration path를 지정해줘야 한다.
userProfile:"https://www.googleapis.com/oauth2/userinfo"
혹은
userProfile:"https://www.googleapis.com/oauth2/v3/userinfo"
를 콜백URL 뒤에 추가한다.
User.findOrCreate() 메서드는 mongoose가 제공하는 메서드가 아닌 유저가 만들어 pull 한 fake method(pseudo code)이다. 그래서 해당 메서드를 실행하려면 findorcreate 패키지를 설치해야 한다.
$ npm install mongoose-findorcreate
설치 후 app.js에서 require 한다.
const findOrCreate = require('mongoose-findorcreate');
passportlocalMongoose 를 plugin 했듯이 스키마가 findorcreate도 plugin 하게
app.use(passport.session()); 를 추가한다.
구글 아이디로 가입할 수 있도록 register.ejs 에 Sign Up with Google 을 추가한다.
구글 아이디 로그인을 위해 login.ejs에 Sign In with Google 을 추가한다.
<a class="btn btn-block" href="/auth/google" role="button">
버튼을 누르면 "/auth/google" 로 이동한다.
여기서 구글에 리다이렉트 URL대로 구현하려면
1번 ('/auth/google') 으로 정보를 요청하고,
요청한 정보를 들고
/auth/google/callback URL로 이동해서
2번 ('/auth/google/callback') 에서 authenticate() 메서드를 통해
성공시 홈라우트('/') 실패 시 로그인 라우트('/login') 으로 이동시킨다.
아래는 1번의 과정이다.
예시에서 보이는대로 strategy는 google, scope는 profile로 설정해서
유저의 구글 profile 즉, 이메일과 아이디를 요청한다.
app.js 에 예시대로 추가한다
app.get('/auth/google', passport.authenticate('google', { scope: ["profile"] }));
코드를 작성하고 Sign Up with Google 를 클릭하면
구글 계정으로 로그인 창이 뜬다.
로그인해서 들어가면
이런 창이 뜨는데 구글에 입력한대로라면 http://localhost:3000/auth/google/secrets 페이지로 이동해야 하는데
app. get('/auth/google/secrets') 메서드를 만들지 않았기 때문이다.
2번 /auth/google/callback get() 메서드 추가
정리하자면
/auth/google ➡
/auth/google/secrets ➡
get("/secrets") ➡
인증 true시 secrets 페이지 / false시 로그인 라우트("/login") 로 간다.
다시 Sign Up with Google을 누르면 이런 오류가 뜬다.
이 오류는 p-l-mongoose 에서 예시로 가져 온
이 코드때문인데 이 코드는 mongodb의 User 스키마에 더해진 객체를 가져와 serialize와 deserialize를 수행하는 것이다.
구글 로그인을 통해 가입하게 되는 경우 User 스키마에 더하는 것이 아닌 구글에 인증을 요청해서 허가를 받아내는 방식으로 수행하게 돼서 오류가 뜬다.
그래서 이 코드를 passport 패키지의 serializeUser() / deserializeUser() 로 변경해야 한다.
콘솔에 구글에 요구한 profile을 로그로 찍어보면 이렇게 나온다.
id : 구글 데이터베이스에 저장된 계정의 아이디로, 내 데이터베이스에 저장된다.
만약 구글 로그인 후에 해당 사이트에서 변경사항이 있다면 이 아이디를 기본키로 사용해서 데이터를 업데이트한다.
mongodb 내에선 구글 로그인을 했을 경우 id 만을 저장하며 데이터 또한 mongodb 식으로 아이디가 자동생성된다.
문제는 가입한 구글아이디로 로그인을 하면 mogodb 내에 user 정보가 또 저장된다는 점이다.
이걸 없애기 위해서는 user 스키마에 googleId 속성을 추가한다.
그리고 findOrCreate() 메서드를 이용해 profile.id 를 googleId에 저장하던가 일치하는 정보를 찾는다.
다시 구글 아이디로 가입하면 googleId가 저장된다.
이렇게 하면 로그인 시에도 새 user로 저장되지 않고,
같은 아이디로 sign in을 다시 해도 googleId가 중복되기 때문에 user에 새로 저장하지 않는다.
그리고 구글에 권한을 요청해서 승인받는 시스템이기 때문에 내 데이터베이스에는 비밀번호가 저장되지 않는다.
또한 당연하게도 구글 아이디로 가입해서 로그아웃을 하면 해당 사이트에서만 로그아웃하는 것일뿐
전체 사이트의 구글아이디 로그아웃 권한이 있는 것이 아니다.
https://lipis.github.io/bootstrap-social/
마지막으로 Social Buttons for Bootstrap 을 이용해 구글로그인 버튼을 변경했다.
'Node.js' 카테고리의 다른 글
[Node.js] Passport, express-session 으로 회원가입, 로그인, 로그아웃 하기 (0) | 2021.06.18 |
---|---|
[Node.js] bcrypt 를 이용해 round salting + hashing 하기 (0) | 2021.06.18 |
[Node.js] MD5 를 이용해 Hash 암호화하기 (0) | 2021.06.18 |
[Node.js] dotenv를 이용해 암호화하기 (0) | 2021.06.18 |
[Node.js] Mongoose - encryption 사용해서 비밀번호 암호화하기 (0) | 2021.06.18 |