Node.js＋Passport＋Google 認証を使ってみた

#Passport とは
Passport は Node.js のための認証ミドルウェアです。認証リクエストをおこなうための必要最低限の機能をもつように設計されています。 
公式 [Passport - Node.jsのための、シンプルで使いどころを選ばない認証モジュール]
(http://knimon-software.github.io/www.passportjs.org/)

#Passport を使ってみた
Passport をインストールして、Google を使ってユーザ認証するところまで、使ってみました。

* node 8.1.14
* express 4.16.2
* passport 0.4.0
* passport-google-oauth 1.0.0

##ワークスペースを作る
まず、Node.js＋Express のワークスペースを作ります。

参考 [Node.js、Express.js入門 - ぺーぺーSEのブログ]
(http://tanakakns.hatenablog.com/entry/20150302/1425285635)

##インストールする

```
$ npm install --save passport
```

参照 [Passport | はじめに]
(http://knimon-software.github.io/www.passportjs.org/guide/)

以下をソースコードに追加します。

```js:app.js
var passport = require('passport');
app.use(passport.initialize());
```

参照 [Passport | 設定]
(http://knimon-software.github.io/www.passportjs.org/guide/configure/) ミドルウェアの設定

##Google 認証を使うための準備

Google 認証を使うために、Google サービスを使用するアプリケーションを事前に登録しておきます。

開発者としての Google アカウントを作っておきます。
その Google アカウントで Google Developer Console にログインします。
まず、プロジェクトを作成します。プロジェクト名は任意です。

参照 [Google APIを使用するための設定（プロジェクトの作成 ・ 使用するAPIの設定）　第１回 - プログラミングノート]
(http://homework.hatenablog.jp/entry/2016/11/24/122643)

続いて、認証情報を作成します。
このとき、「OAuth クライアント ID」を選びます。
アプリケーションの種類は「ウェブアプリケーション」。
名前は任意です。
リダイレクト URL を設定します。設定すべき値は後述します。◆
「作成」すると、「クライアント ID」「クライアントシークレット」が取得できます。

参照 [Google APIを使用するための設定（認証情報の登録）　第２回 - プログラミングノート]
(http://homework.hatenablog.jp/entry/2016/11/30/134132)

加えて、Google+ API を有効にしておきます。

参照 [Google API を有効にする | MAGELLAN BLOCKS]
(https://www.magellanic-clouds.com/blocks/guide/enable-google-apis/)

これをしていないと実行時にエラーになります。

参照 [Google Authentication Not Working · Issue #49 · scotch-io/easy-node-authentication · GitHub]
(https://github.com/scotch-io/easy-node-authentication/issues/49)

##Google を使って認証するための準備

Passport を使って認証確認する処理を書きます。

まず、認証ストラテジをインストールします。

```
$ npm install --save passport-google-oauth
```

以下をソースコードに追加します。

```js:app.js
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
passport.use(new GoogleStrategy({
        clientID: "上記で取得したクライアント ID",
        clientSecret: "上記で取得したクライアントシークレット",
        callbackURL: "上記で設定したロールバック URL"
    }, function(accessToken, refreshToken, profile, done){
        ◇◇  // ここで profile を確認して結果を返す
    }
));
```

結果を返すところは、

```js:
        if (profile) {
            return done(null, profile);
        }
        else {
            return done(null, false);
        }
```

この辺は [Passport > Documentation > Google]
(http://www.passportjs.org/docs/google)

##ログイン URL を用意する

ここで用意された URL にアクセスすると、Google に認証を委譲します。

```js:app.js
app.get('/auth/google', passport.authenticate('google', {
    scope: ['https://www.googleapis.com/auth/plus.login']
}));
```

##ログイン画面を用意する

ログイン画面、例えば login.html を用意します。上記で準備した URL へのリンクを含めます。

```html:login.html
<a href="/auth/google">Google でログインする</a> 
```

/login に GET するとこの画面を表示するようにしておきましょう。

```js:app.js
app.get('/login', function(req, res){
    res.sendFile(__dirname + '/◇◇/login.html');
});
```

##コールバック URL を用意する

Google で認証されると、コールバック先として事前に登録しておいた URL に飛んできます。
つまり、ここで用意した URL は、前述した Google 認証情報の設定で使用します。設定で使用するときは、相対パスでなく絶対パスを使います。

```js:app.js
app.get('/auth/google/callback', 
    passport.authenticate('google', 
    function(req, res) {
        ◇◇  // 認証に成功したときの処理
    })
);
```

認証されると通常はページ遷移します。↓

```js:app.js
app.get('/auth/google/callback', 
    passport.authenticate('google', 
    function(req, res){
        res.redirect('/◇◇');
    })
```

遷移先はオプション指定で済ませられます。↓

```js:app.js
app.get('/auth/google/callback', 
    passport.authenticate('google', {
        failureRedirect: '/◆◆',  // 失敗したときの遷移先
        successRedirect: '/◇◇',  // 成功したときの遷移先
    },
    function(req, res){
```

認証成功したときは URL 遷移せずに処理することが多いでしょうか。

```js:app.js
app.get('/auth/google/callback', 
    passport.authenticate('google', {
        failureRedirect: '/◆◆',  // 失敗したときの遷移先
    },
    function(req, res){
        ◇◇  // 成功したときの処理
```

##セッションを無効にして使う

Passport は認証成功したとき認証情報をセッションに保存します。API サーバとして実行するときは、リクエストごとに認証処理する必要があります。このときはセッションを無効にして使用します。

```js:app.js
app.post('/login',
    passport.authenticate('google', {
        session: false,
```

この辺までは [Passport | 認証]
(http://knimon-software.github.io/www.passportjs.org/guide/authenticate/)

##セッションを有効にして使う

Passport は認証成功したとき認証情報をセッションに保存します。Express でセッションを使えるようにしておきましょう。

```
$ npm install --save express-session
```

```js:app.js
var session = require('express-session');
app.use(session({
    secret: '○○',
}));
app.use(passport.session());

passport.serializeUser(function(user, done) {
    done(null, user);
});

passport.deserializeUser(function(user, done) {
    done(null, user);
});
```

この辺は [Passport | 設定]
(http://knimon-software.github.io/www.passportjs.org/guide/configure/) セッション管理に関する設定

##どのページでも認証確認する

これまでのコードでは、ログイン画面以外のページでは認証確認されません。どのページでも認証確認されるようにしましょう。

まず、ページのリクエストを貰ったとき認証済か確認する関数を用意します。

```js:app.js
function isAuthenticated(req, res, next){
    if (req.isAuthenticated()) {  // 認証済
        return next();
    }
    else {  // 認証されていない
        res.redirect('/login');  // ログイン画面に遷移
    }
}
```

ページごとに確認処理を入れるようにします。例えば、

```js:app.js
app.get('/◆◆', isAuthenticated, function(req, res){
    ◇◇  // 認証済のとき実行される
```

参考 [express - Documentation for "ensureAuthentication" "isAuthenticated" passport's functions? - Stack Overflow]
(http://stackoverflow.com/questions/14188834/documentation-for-ensureauthentication-isauthenticated-passports-functions)