Node.js+Expressの環境で認証機能を実装する
Passportを使うと、Node.js+Expressの環境に認証機能を実装できます。
本記事は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()); より後に追加.
ログイン処理で記述したsession
をtrue
にします。
{ 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;