Node.js + Express + passport-twitterで認証Webアプリをつくる


[Node.js+Express+MongoDBでWeb APIをつくる](http://qiita.com/itagakishintaro/items/a1519998a91061cbfb1e)の続き的な感じで。

# passportなどのインストール

passportは、Node.jsで使える認証用ミドルウェア。
http://passportjs.org/

```package.json
{
	"name": "passport-twitter",
	"version": "0.0.1",
	"private": true,
	"dependencies":{
		"express": "*",
		"passport": "*",
		"passport-twitter": "*",
		"express-session": "*"
	}
}

```

package.jsonに追記したら、例のごとくインストール。

```
npm install
```

# コードを書く

## app.js

まずは、本体のapp.js。

http://passportjs.org/guide/twitter/

```js
// passport-twitter用
var session = require('express-session')
var auth = require('./passport');
var passport = auth.passport;
```

と

```js
// passport-twitter用
app.use(passport.initialize()); 
app.use(passport.session()); 
app.use(session({secret: 'itagaki'}));
```

がpassport-twitter用の部分。
passport部分は`require('./passport')`で別のファイルに外出ししている。
また、ルーティング部分も`require('./routes')`で別ファイルに外出ししているので、`routes.configRoutes(app, server, passport)`でルーティング設定メソッドに`passport`を渡しています。

```app.js
'use strict';
var http = require('http');
var express = require('express');
// passport-twitter用
var session = require('express-session')
var auth = require('./passport');
var passport = auth.passport;
// ルーティングファイルを指定
var routes = require('./routes');
var app = express();
var server = http.createServer(app);

// passport-twitter用
app.use(passport.initialize()); 
app.use(passport.session()); 
app.use(session({secret: 'itagaki'}));
// 静的ファイルのルートディレクトリを指定
app.use(express.static(__dirname + '/public'));
// ルーティングを設定
routes.configRoutes(app, server, passport);
// リッスン
server.listen(3000);
console.log('Listening on port %d in %s mode', server.address().port, app.settings.env);
```

## passport.js

passport.jsという名前は別に決まりでも何でもないので、注意。
KEYとSECRETは
https://apps.twitter.com/
で取得する。

基本は
http://passportjs.org/guide/twitter/
のコードのとおりなんだけど、Session部分は少し理解しにくい。
バージョンによっても少し書き方が違うみたいで、インターネットで情報を探してそのまま書いても動かないことがある。
結局は最新の公式サイトをみるのが一番早いかも。
http://passportjs.org/guide/configure/

```passport.js
// http://passportjs.org/guide/twitter/
var TWITTER_CONSUMER_KEY = 'TWITTER_CONSUMER_KEY';
var TWITTER_CONSUMER_SECRET = 'TWITTER_CONSUMER_SECRET';
var passport = require('passport')
  , TwitterStrategy = require('passport-twitter').Strategy;

// Sessionの設定
// http://passportjs.org/guide/configure/
passport.serializeUser(function(user, done) {
    done(null, user.id);
});
passport.deserializeUser(function(obj, done) {
    done(null, obj);
});

passport.use(new TwitterStrategy({
    consumerKey: TWITTER_CONSUMER_KEY,
    consumerSecret: TWITTER_CONSUMER_SECRET,
    callbackURL: "http://localhost:3000/auth/twitter/callback"
  },
  function(token, tokenSecret, profile, done) {
  	passport.session.id = profile.id;

  	// tokenとtoken_secretをセット
  	profile.twitter_token = token;
    profile.twitter_token_secret = tokenSecret;

    process.nextTick(function () {
    	return done(null, profile);
    });
  }
));

module.exports = {passport: passport};
```

## routes.js

例えば、secret/secret.htmlに認証をかけたいならこんな感じ。
先ほどのpassport.jsで`done(null, user.id);`としたので、`passport.session.id`という感じでSessionからidを取得できる。
この場合は、Sessionにidがあれば、secret.htmlを表示するようにしている。
ちなみに`fs.readFile`は単にファイルを読み込んでいるだけ。

```routes.js
'use strict';
var configRoutes;
var fs = require('fs');

configRoutes = function(app, server, passport) {
    app.get('/secret', function(request, response) {
        // 認証保護
        if(passport.session && passport.session.id){
            fs.readFile('./secret/secret.html', 'utf8', function (error, html) {
                response.send(html);
            });
        } else {
            response.redirect('/login');
        }   
    });

    // passport-twitter ----->
    // http://passportjs.org/guide/twitter/
    app.get('/auth/twitter', passport.authenticate('twitter'));
    app.get('/auth/twitter/callback', 
        passport.authenticate('twitter', { successRedirect: '/secret',
                                                failureRedirect: '/login' }));
    // <-----
}

module.exports = {configRoutes: configRoutes};
```

# コード全体

[Node.js+Express+MongoDBでWeb APIをつくる](http://qiita.com/itagakishintaro/items/a1519998a91061cbfb1e)の続きなので、passport-twitterと関係ない部分があるので、少しわかりにくいかもしれませんが。。。

https://github.com/itagakishintaro/MongoExpressNode/tree/passport