Node.js+Expressの環境で認証機能を実装する

Passportを使うと、Node.jsExpressの環境に認証機能を実装できます。
本記事はNode.js+Express+Passportの基本的な使い方になります。

インストール

まず、必要なモジュールをインストールします。

Passport

npm install passport

認証ストラテジ

npm install passport-local

body-parser

フォームの入力を受け取るために必要です。

npm install body-parser

認証の実装方法

下記コードは最低限の処理を記述した認証処理の例です。入力値がuser1と一致かどうかを判定しています。

// ユーザー情報
const User1 = {
  username: "user1",
  password: "123"
};

const express = require('express');
const app = express();

const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bodyParser = require('body-parser');

app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));

passport.use(new LocalStrategy(
  {
    // フィールド名が、username, password以外の場合.
    usernameField: 'login-id',
    passwordField: 'password',
    session: false,
  },
  (username, password, done) => {
    // 検証用コールバック.
    if (username !== User1.username) {
      return done(null, false);
    }
    if (password !== User1.password) {
      return done(null, false);
    }
    return done(null, username);
  }
));

app.use(passport.initialize());
フォームのユーザ名とパスワードのフィールド名はそれぞれusername, passwordとする必要があります。
それ以外のフィールド名にする場合はusernameField, passwordFieldを使って指定が必要です。(上記サンプルではユーザ名フィールドをlogin-idとしています)

ログイン処理

ログイン処理は次のように記述します。successRedirectに認証成功時に表示するページを、failureRedirectに認証失敗時に表示するページを指定します。

app.post('/login', passport.authenticate('local', { successRedirect: 'ok.html',
                                                    failureRedirect: 'login.html',
                                                    session: false,
  }));

上記では/loginにPOSTで入力値が渡ってきたときに前述の認証が実行されます。その後、認証結果に応じて表示するページを指定しています。

次のようにsuccessRedirectをコールバックで記述することもできます。

app.post('/login', passport.authenticate('local', { failureRedirect: 'login.html',
                                                    session: false,
  }),
  (request, response) => {
    console.log('login ok');
    response.sendFile(path.join(__dirname, 'public/ok.html'));
  });

ログアウト処理

app.get('/logout', (request, response) => {
  request.logout();
  response.redirect('/');
});

各ページで認証確認する

各ページで認証確認をしないと直接URLを指定すればページが見えてしまいます。各ページで認証済みかどうか確認する処理を追加します。

準備

認証済みかどうかを判定するためにはセッションを有効にしなければいけません。

express-sessionをインストールします。

npm install express-session

次の処理を追加します。

const session = require('express-session');
app.use(session({
    secret: 'keyboard cat',
    resave: true,
    saveUninitialized: false,
  }));

app.use(passport.session());  // <- app.use(passport.initialize()); より後に追加.

ログイン処理で記述したsessiontrueにします。

{ successRedirect: 'ok.html',
  failureRedirect: 'login.html',
  session: true,
}

シリアライズメソッドデシリアライズメソッドを作成します。

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

passport.deserializeUser((user, done) => {
  done(null, user);
});

各ページ(ルーティング)での記述

次のようにルーティングに認証メソッドを指定して認証確認します。

変更前

app.get('/list', (request, response) => {
  response.sendFile(path.join(__dirname, 'public/list.html'));
});

変更後

app.get('/list', isAuthenticated, (request, response) => {
  // 認証済みの場合の処理.
  response.sendFile(path.join(__dirname, 'public/list.html'));
});

function isAuthenticated(request, response, next) {
  if (request.isAuthenticated()) {
    // 認証済みの場合の処理へ.
    return next();
  }

  // 認証していない場合の処理.
  console.warn("not authenticated.");
  response.redirect('/');
}
app.use(passport.session());より後にルーティングを記述しないと、認証済みと判定されないので注意してください。
(app.use(passport.session());より後にルーティングを記述しないと、Requestにセッションが入らない)

認証メソッドを用意せずに各ルーティングで認証確認をする場合は次のようになります。

app.get('/forms', (request, response) => {
  if (request.isAuthenticated()) {
    // 認証済みの場合の処理.
    response.sendFile(path.join(__dirname, 'public/forms.html'));
    return;
  }

  // 認証していない場合の処理.
  console.warn("not authenticated.");
  response.redirect('/');
});

セッション情報の取得

検証用コールバックでの指定により、ルーティングでの値取得方法が異なります。

return done(null, username);

とした場合、

const username = request.user;

usernameが取得できます。

return done(null, { username: username });

とした場合、分割代入でusernameを取得します。

const { username } = request.user;
このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

コメント

メールアドレスが公開されることはありません。 が付いている欄は必須項目です