OAuth 를 구조적으로 제공하는 passport.js 인증 미들웨어를 소개한다. passport 의 인증API 는 알고나면 간단한데, 처음에 Wall 이 있다. 이를 Node.js 입문자에게 꼭 해결해주고 싶어 이 글을 작성한다.
이 글은, Twitter, Facebook, Google 총 3편으로 연재할 것이다.

이번편을 OAuth+App을 10분안에 제작하는 것에 목표를 둔다. 목표를 달성하면, Facebook, google 은 5분만에 달성하게 될 것이다.
최근 내가 제작한 nodestatic 을 사용한다. 이것은 최소의 코드로 원하는 웹서버를 관리할 수 있다.
한국 개발자들은
그리하여, 최소한의 웹서버만 관리해주는 것을 제작하였다.
$ curl nodestatic.com | bash
passport, passport-twitter 2개의 모듈을 설치한다.
$ npm install passport --save
$ npm install passport-twitter --save
그리고, login session 변수를 html 에서 구분할 수 있도록 ejs template module 을 설치한다.
$ npm install ejs --save
--save 옵션은 package.json dependencies property 에 자동추가되는 역할을 한다.
디렉토리/파일 구성내용이다.
./passport_project/
404.html
init*
package.json
static-app.js
node_modules
passport
passport-twitter
package.json 파일을 확인하자.
{
...
...
"dependencies": {
"express": "*",
"ejs": "*",
"passport": "*",
"passport-twitter": "*"
},
...
}
OAuth 를 사용하기 위해서는 각 서비스에 App 을 등록해야 한다.
twitter dev center 에 로그인하여, App 을 등록하자.
그리고, Consumer key / secret 2개의 정보를 복사하여, package.json 파일에 등록하고, 이를 나중에 사용하자.
callbackURL 은 중요하니 아래 내용 중 your_host 부분만 수정하자.
{
...
"oauth": {
"twitter": {
"TWITTER_CONSUMER_KEY": "yzTvZFr.......ykrqQA",
"TWITTER_CONSUMER_SECRET": "spAgPbBELJk7................HbQc9LbVlMkQ",
"callbackURL": "http://your_host/auth/twitter/callback"
}
},
...
}
passport 관련 작업을 시작하자
main 파일이다.
/**
* Static simple web server
* Only use Express module
*
* @author nanhaprk <nanhap@gmail.com>
* @homepage http://nodeqa.com
*/
//
// Usage
//
if (process.argv[2] == '-h') return console.log('Usage: node ./static-app.js [port] [process_title]\ n');
//
// ps on linux
//
process.title = process.argv[3] || 'nodestatic.com : Static WebServer';
//
// declare
//
var express = require('express'),
fs = require('fs');
var port = parseInt(process.argv[2], 10) || 8080;
var app = express();
// --------
// !! 아래 부분을 추가하자. ejs 와 session
//
app.set('views', __dirname);
app.set('view engine', 'ejs');
app.use(express.cookieParser());
app.use(express.session({
key : 'sid',
secret : 'secret'
}));
// --------
//
// static serving
//
app.use(express.static(__dirname));
//
// **oauth.js** 파일에 OAuth 관련 설정을 하자. app 객체를 전달하자.
//
require('./oauth')(app);
app.get('/', function(req, res) {
//
// 세션정보를 확인한다.
//
console.log(req.session);
//
// req.user 는 아래에서 설명한다.
// 처음에 undefined 이나, 로그인 성공하면, profile 정보가 저장된다.
//
console.log(req.user);
res.render('index', { user: req.session.passport.user || {} });
});
//
// 404 page
//
app.get('*', function(req, res) {
res.type('html').send(404, fs.readFileSync('404.html'));
});
//
// listen
//
app.listen(port, function() {
console.log("[36mStart static server, listen port: " + port + '[39m')
});
module.exports = init;
function init(app) {
var pkginfo = require('./package');
var passport = require('passport');
app.use(passport.initialize());
app.use(passport.session());
TwitterStrategy 를 추가한다.
var TwitterStrategy = require('passport-twitter').Strategy;
Twitter 에 정보를 전달하고 받을 경우에 사용되어진다.
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
Comsumer 정보를 설정한다.
passport.use(new TwitterStrategy({
consumerKey: pkginfo.oauth.twitter.TWITTER_CONSUMER_KEY,
consumerSecret: pkginfo.oauth.twitter.TWITTER_CONSUMER_SECRET,
callbackURL: pkginfo.oauth.twitter.callbackURL
}, function(token, tokenSecret, profile, done) {
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// req.session.passport 정보를 저장하는 단계이다.
// done 메소드에 전달된 정보가 세션에 저장된다.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
return done(null, profile);
}));
위에서 profile 정보는 Http Client Request (req) 객체의 user property 에 자동 할당된다.
기본적인 twitter Strategy 의 route 이다.
...
app.get('/auth/twitter', passport.authenticate('twitter'));
//
// redirect 실패/성공의 주소를 기입한다.
//
app.get('/auth/twitter/callback', passport.authenticate('twitter', {
successRedirect: '/',
failureRedirect: '/'
}));
app.get('/logout', function(req, res){
//
// passport 에서 지원하는 logout 메소드이다.
// req.session.passport 의 정보를 삭제한다.
//
req.logout();
res.redirect('/');
});
}
메인 HTML 파일이다.
<a href="/auth/twitter">twitter login</a>
<% if (user.username) { %>
<a href="/logout">logout</a>
<%= user.username %>
<% } %>
$ ./init start 8082 passport_app
Starting static webserver: PID: 4252
$ ./init stop
Stopping static webserver: PID: 4252
$ open localhost:8082
login 버튼을 클릭하고, req.session 을 확인하면, 아래와 같은 정보를 확인할 수 있다.
{ cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
passport:
{ user:
{ provider: 'twitter',
id: 41317247,
username: 'nanhapark',
displayName: '나나하치',
photos: [Object],
/logout 을 수행하면 session 정보는 아래와 같아진다.
{ cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
passport: {} }jjj
혹은 로그인 확인하는 다른 방법은 req.isAuthenticated() 메소드를 사용하는 것이다. 반환값은 true/false 이다.
이제 누구나 OAuth 인증을 도입할 수 있게 될 것이다. 다음편에는 Facebook 편을 연재하겠다.