node js는 패스포트를 이용하면, 거의 모든 SNS 로그인을 구현할 수 있습니다. 하지만, 새로운 SNS 사이트나 OAuth 2.0 기능을 가진 사이트의 요청을 필요로 할 때를 대비해 기능을 잘 알아 둘 필요가 있습니다. 그리고 모듈을 쓸 필요도 없을 만큼 매우 간단하고 쉽습니다.
[공식 문서]
구글 OAuth 2.0 OverView : https://developers.google.com/identity/protocols/OAuth2?hl=ko .
구글 OAuth 2.0 for Web Server Applications : https://developers.google.com/identity/protocols/OAuth2WebServer?hl=ko .
유저 프로필 요청 : https://developers.google.com/gmail/api/v1/reference/users/getProfile .
[주요 사이트]
Google APIs 콘솔 : https://console.developers.google.com .
[참고 문서]
php를 이용한 Google OAuth2.0 Login : https://nicgoon.tistory.com/208 . (전반부 구글 클라우드 콘솔 설정 숙지.).
1. 준비사항.
1) 본 문서를 보기전, 구글 클라우드 API에서 클라이언트 ID를 만들어야 합니다. 해당 내용은 위 참고 문서 php를 이용한 Google OAuth2.0 Login 부분을 참고 하시면됩니다.
2) 익스프레스 서버 설정.
익스프레스를 이용해 서버를 설정하였다면, 웹을 처리를 할 라우트를 만들어 주세요 저는 아래와 같이 라우트 주소를 설정하였습니다.
구글 로그인 라우트 기본 주소 : http://localhost/oauth2
인증코드 요청 페이지 : http://localhost/oauth2/request_code
토큰 교환 페이지 : http://localhost/oauth2/exchange_token
3) 클라이언트 아이디 관련 값들.
클라이언트 아이디 : 107557211118-lpfm0l4gs5ffpas8cbjn5bp71f2hbag5.apps.googleusercontent.com
클라이언트 보안 비밀 : NaJSvmGdShGg1kkXkGdvHp4T
리디렉션 페이지 : http://localhost/oauth2/exchange_token
2. 라우트 기본 뼈대.
구글 로그인에서 사용되는 페이지는 최소 2개이고, 이 것을 저는 라우트를 하나 만들어 다음과 같은 코딩을 했습니다. request_code 는 인증코드 요청페이지, exchange_token 은 리디렉션 후 토큰 교환 입니다.
var express = require('express');
var router = express.Router();
/* GET home page. */
router.use('/:name', function(req, res, next) {
// 요청한 파일명을 가지고 오는 메소드 입니다.
let methodName = req.params.name;
// 인증 코드를 요청한 경우 처리 분기 입니다.
if( methodName == "request_code" )
{
request_code(req, res, next);
return; // 리턴 중요.
}
// 토큰 교환을 요청한 경우 처리 분기 입니다.
else if( methodName == "exchange_token" )
{
exchange_token(req, res, next);
return; // 리턴 중요.
}
// 처리 방법을 확인하지 못한 경우. next 처리를 하도록 합니다.
next();
});
// 인증 코드를 요청한 경우 처리 하는 메소드 입니다.
function request_code( req, res, next )
{
res.setHeader( "Content-Type", "text/html; charset=UTF-8" );
res.end( "코드 요청하는 메소드." );
}
// 토큰 교환 및 사용자 정보를 확인하는 경우 처리하는 메소드 입니다.
function exchange_token( req, res, next )
{
res.setHeader( "Content-Type", "text/html; charset=UTF-8" );
res.end("토큰을 교환하는 메소드.");
}
module.exports = router;
3. 유저 로그인 페이지 리디렉션하기.
주소를 만들때, 사용되는 옵션은 문서 처음에 있는 [구글 OAuth 2.0 for Web Server Applications] 링크를 참고 하시기 바립니다.
request_code 부분에 인증을 위한 주소를 만들어 리디렉션 하면, 사용자는 구글 로그인 창을 보게 됩니다. 코드는 아래와 같습니다.
// 인증 코드를 요청한 경우 처리 하는 메소드 입니다.
function request_code( req, res, next )
{
// 공통적으로 사용하는 상수들 입니다.
var scope = "https://mail.google.com/";
var client_id = "107557211118-lpfm0l4gs5ffpas8cbjn5bp71f2hbag5.apps.googleusercontent.com";
var client_secret = "NaJSvmGdShGg1kkXkGdvHp4T";
var redriect_url = "http://localhost/oauth2/exchange_token";
// 인증을 위한 주소를 만들어 줍니다.
let reqAddr = "https://accounts.google.com/o/oauth2/v2/auth"
+ "?client_id=" + client_id
+ "&redirect_uri=" + encodeURIComponent( redriect_url )
+ "&scope=" + encodeURIComponent( scope )
+ "&state=OK"
+ "&access_type=offline"
+ "&include_granted_scopes=true"
+ "&response_type=code"
;
res.redirect( reqAddr );
}
로그인 하고, 권한도 모두 주면, 리디렉션 페이지가 호출 됩니다. 우리는 여기서, 토큰 교환을 시도할 것 입니다.
4. 토큰 교환 처리.
정식 문서를 보면, 아래와 같은 값을 보내면, 토큰을 주는 것으로 되어 있습니다.
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https://oauth2.example.com/code&
grant_type=authorization_code
우리가 받은 토큰 값등을 활용해 위의 페이지를 만들 것 입니다.
1) 리퀘스트 설치.
페이지를 요청하는 데 리퀘스트 객체를 사용할 것 입니다. 아래와 같이 리퀘스트를 설치해 주도록 합니다.
npm i request
2) 토큰 교환.
보내야 할 데이터 중 헤더 부분은 request가 알아서 채워 줍니다. (POST로 보낼 때 당연히 적어야할 부분). 그래서 데이터부분만 적어 주면됩니다. exchange_token 메소드를 다음과 같이 변경해 보도록 합니다.
// 토큰 교환 및 사용자 정보를 확인하는 경우 처리하는 메소드 입니다.
function exchange_token( req, res, next )
{
// 요청할 데이터를 만들어 줍니다.
let requestOption = {
url:'https://www.googleapis.com/oauth2/v4/token',
method:'POST',
form:{
code:req.query.code,
client_id:client_id,
client_secret:client_secret,
redirect_uri: redriect_url,
grant_type: 'authorization_code'
}
};
request.post( requestOption, function( err, httpResponse, body ){
res.setHeader( "Content-Type", "text/html; charset=UTF-8" );
// 오류가 난 경우 오류를 반환해 줍니다.
if( err )
{
res.end("오류가 났습니다.<br>" + err);
return;
}
res.end( body );
});
}
그리고 실행하면 정상적인 경우 다음과 같은 응답을 화면에 뿌려 줍니다. (자세히 보면 Access Token을 받아 온 것을 확인할 수 있을 것 입니다.)
5. 사용자 정보 가지고 오기.
교환된 토큰으로 아래와 같이 함수를 만들어 body와 res 값을 넣어 주면, 화면에 사용자 정보를 표시해 줍니다.
// 토큰 교환 및 사용자 정보를 확인하는 경우 처리하는 메소드 입니다.
function exchange_token( req, res, next )
{
// 요청할 데이터를 만들어 줍니다.
let requestOption = {
url:'https://www.googleapis.com/oauth2/v4/token',
method:'POST',
form:{
code:req.query.code,
client_id:client_id,
client_secret:client_secret,
redirect_uri: redriect_url,
grant_type: 'authorization_code'
}
};
request.post( requestOption, function( err, httpResponse, body ){
res.setHeader( "Content-Type", "text/html; charset=UTF-8" );
// 오류가 난 경우 오류를 반환해 줍니다.
if( err )
{
res.end("오류가 났습니다.<br>" + err);
return;
}
// res.end( body );
bodyobj = JSON.parse( body );
read_profile( res, bodyobj.access_token );
});
}
// 유저 정보를 확인하는 메소드 입니다.
function read_profile( res, token )
{
// 요청할 데이터를 만들어 줍니다.
let requestOption = {
url:'https://www.googleapis.com/gmail/v1/users/me/profile',
headers:{
'Authorization': 'Bearer ' + token
},
rejectUnauthorized:false
};
request.get( requestOption, function( err, httpResponse, body ){
if( err )
{
res.end("사용자 정보를 확인하던 중 오류가 났습니다.<br>" + err);
return;
}
// 사용자 정보를 출력합니다.
res.end( body );
});
}
별다은 오류가 없다면 다음과 같은 페이지를 볼 수 있을 것 입니다.
6. 전체 소스
익스프레서 서버에서 사용하기 위한 전체 소스 코드는 아래와 같습니다.
var express = require('express');
var router = express.Router();
var request = require('request');
// 공통적으로 사용하는 상수들 입니다.
var scope = "https://mail.google.com/";
var client_id = "107557211118-lpfm0l4gs5ffpas8cbjn5bp71f2hbag5.apps.googleusercontent.com";
var client_secret = "NaJSvmGdShGg1kkXkGdvHp4T";
var redriect_url = "http://localhost/oauth2/exchange_token";
/* GET home page. */
router.use('/:name', function(req, res, next) {
// 요청한 파일명을 가지고 오는 메소드 입니다.
let methodName = req.params.name;
// 인증 코드를 요청한 경우 처리 분기 입니다.
if( methodName == "request_code" )
{
request_code(req, res, next);
return; // 리턴 중요.
}
// 토큰 교환을 요청한 경우 처리 분기 입니다.
else if( methodName == "exchange_token" )
{
exchange_token(req, res, next);
return; // 리턴 중요.
}
// 처리 방법을 확인하지 못한 경우. next 처리를 하도록 합니다.
next();
});
// 인증 코드를 요청한 경우 처리 하는 메소드 입니다.
function request_code( req, res, next )
{
// 인증을 위한 주소를 만들어 줍니다.
let reqAddr = "https://accounts.google.com/o/oauth2/v2/auth"
+ "?client_id=" + client_id
+ "&redirect_uri=" + encodeURIComponent( redriect_url )
+ "&scope=" + encodeURIComponent( scope )
+ "&state=OK"
+ "&access_type=offline"
+ "&include_granted_scopes=true"
+ "&response_type=code"
;
res.redirect( reqAddr );
}
// 토큰 교환 및 사용자 정보를 확인하는 경우 처리하는 메소드 입니다.
function exchange_token( req, res, next )
{
// 요청할 데이터를 만들어 줍니다.
let requestOption = {
url:'https://www.googleapis.com/oauth2/v4/token',
method:'POST',
form:{
code:req.query.code,
client_id:client_id,
client_secret:client_secret,
redirect_uri: redriect_url,
grant_type: 'authorization_code'
}
};
request.post( requestOption, function( err, httpResponse, body ){
res.setHeader( "Content-Type", "text/html; charset=UTF-8" );
// 오류가 난 경우 오류를 반환해 줍니다.
if( err )
{
res.end("오류가 났습니다.<br>" + err);
return;
}
// res.end( body );
bodyobj = JSON.parse( body );
read_profile( res, bodyobj.access_token );
});
}
// 유저 정보를 확인하는 메소드 입니다.
function read_profile( res, token )
{
// 요청할 데이터를 만들어 줍니다.
let requestOption = {
url:'https://www.googleapis.com/gmail/v1/users/me/profile',
headers:{
'Authorization': 'Bearer ' + token
},
rejectUnauthorized:false
};
request.get( requestOption, function( err, httpResponse, body ){
if( err )
{
res.end("사용자 정보를 확인하던 중 오류가 났습니다.<br>" + err);
return;
}
// 사용자 정보를 출력합니다.
res.end( body );
});
}
module.exports = router;
'Node.js' 카테고리의 다른 글
node js 파일 업로드 multer (0) | 2019.05.24 |
---|---|
node.js nodemailer gmail (0) | 2019.05.24 |
node.js를 이용한 iOS Push 구현하기 (requests to APNs) (0) | 2019.04.14 |
Android 결제 서버 개발 (0) | 2019.04.09 |
node.js FCM (Push Notification) 서버 환경 구축하기 (1) | 2019.04.06 |