passportとは
passportはNode.jsで利用できる認証ミドルウェア(モジュール)です。
passportを利用することで、アプリに簡単にOAuth認証を組み込むことができます。
OAuth認証に関して、こちらの記事がすごく分かりやすいので読んでみてください。
一番分かりやすい OAuth の説明
passportの凄いところは、FacebookやTwitter、Googleなど、多くのアカウント認証を利用できる点です。
今回は、ExpressというNode.jsのフレームワークがグローバルインストールされている前提で進んでいきます。
参考:Expressフレームワークのインストールと簡単な使い方
passportを利用して、Facebook認証をしてみる
Facebook Developersでアプリを作成
まずは、Facebook認証を利用するために、https://developers.facebook.com/ からアプリケーションの作成を行なってください。
作成ができたら、アプリの設定ページで以下のように、アプリIDとapp secretが作成されています。
このアプリIDとapp secretは、後で利用することになります。
passportで使うモジュールのインストール
続いて、passportモジュールのインストールを始めます。
以下のコマンドを入力してください。
$ express --view=pug passport-demo
$ cd passport-demo
$ npm install
$ npm init -y
$ npm install passport
$ npm install passport-facebook
$ npm install express-session
・1行目でプロジェクトを行う
passport-demo
ディレクトリを作成しています。このディレクトリの名前はなんでも大丈夫です。
・2行目は、1行目で作成したpassport-demo
ディレクトリに移動しています。
・3行目は依存モジュールのインストールを行なっています。
・4行目は、初期化処理を行い、package.json
を生成しています。
npm init
を行うと普通はどういうパッケージにするか質問がされるのですが、-y
オプションを作ることで、すべてyesの回答となり、その質問を省略することができます。
・5、6行目でpassport
モジュールとpassport-facebook
モジュールをインストールしています。
・7行目は、Express
でセッションを利用できるようにするためのモジュールです。認証した結果をサーバーがセッション情報として保存してくれます。
念の為、この段階で以下のコマンドを実行し、expressがうまく起動できているか確認します。
$ PORT=8000 npm start
http://localhost:8000/ にアクセスしてみてください。
Express
Welcome to Express
という画面が表示されたら、問題ありません。
必要なディレクトリ・ファイルを作る
今回は以下のようなファイル構造にします。
// *は新しく作成するファイル
passport-demo
|- package.json
|- package-lock.json
|- app.js
|- /routes
|- index.js
|- login.js *
|- logout.js *
|- /bin
|- www
|- /views
|- login.pug *
|- index.pug
|- layout.pug
|- /public
|- /node_modules
・
app.js
はpassport
モジュールの設定などを書き込むファイルです。
・localhost:8000/
にアクセスしたときの処理を書き込みます。
・login.js
とlogout.js
は、/login
と/logout
にアクセスしたときの処理を書き込みます。
・www
はサーバーの起動などを担当します。
・login.pug
は/login
にアクセスした時のログイン画面を表示します。
・index.pug
は/
にアクセスした時の画面を表示します。
・layout.pug
はlogin.pug
とindex.pug
の基本となる表示を担当します。
続いて、以上のような認証の際に必要なファイルやディレクトリの作成、その記述を行なっていきます。すでに存在しているファイルの作成は不要なので、以下のファイルだけを作成します。
$ touch routes/login.js
$ touch routes/logout.js
$ touch views/login.pug
ファイルに処理の記述を行う。
続いては、処理の記述を行なっていきます。
まずは、今あるapp.jsの記述を削除して、app.jsに以下の処理を記述してください。
var createError = require('http-errors');
//expressモジュールの読み込み
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
//passportモジュールの読み込み
var passport = require('passport');
//passport-facebookモジュールの読み込み
var Strategy = require('passport-facebook').Strategy;
//先ほど作成したアプリIDを変数に代入
var FACEBOOK_APP_ID = '44923726XXXXXX';
//先ほど作成したapp secretを変数に代入
var FACEBOOK_APP_SECRET = '170dde4751f2ee9d44140b8826457b63';
//passportモジュールによるシリアライズの設定
passport.serializeUser(function(user, done) {
done(null, user);
});
//passportモジュールによるデシリアライズの設定
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
////passport-facebookモジュールのStarategy設定
passport.use(new Strategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
//facebook認証をするためのページの設定(固定)
callbackURL: "http://localhost:8000/auth/facebook/callback",
//プロフィールのどの情報を受け取ることができるかの設定
profileFields: ['id', 'displayName']
},
function (accessToken, refreshToken, profile, done) {
//認証後にdone関数を返すために、process.nextTick関数を利用している
process.nextTick(function () {
return done(null, profile);
});
}
));
//index.jsの処理を利用するために変数に代入
var indexRouter = require('./routes/index');
//users.jsの処理を利用するための処理を変数に代入
var usersRouter = require('./routes/users');
//login.jsの処理を利用するための処理を変数に代入
var loginRouter = require('./routes/login');
//logout.jsの処理を利用するための処理を変数に代入
var logoutRouter = require('./routes/logout');
//expressモジュールを利用するためにapp変数に代入
var app = express();
//アプリケーションで利用するミドルウェアの設定
app.use(require('morgan')('combined'));
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(require('express-session')({ secret: 'keyboard cat', resave: true, saveUninitialized: true }));
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// viewsディレクトリの設定
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
//passportのの初期化
app.use(passport.initialize());
//ログイン後のセッション管理の設定
app.use(passport.session());
//localhost:8000/にアクセスした時にindexRouterの処理がなされる設定
app.use('/', indexRouter);
//localhost:8000/usersにアクセスした時にusersRouterの処理がなされる設定
app.use('/users', usersRouter);
//localhost:8000/auth/facebookにGETアクセスした時に認証リクエストを行う設定
app.get('/auth/facebook',
passport.authenticate('facebook')
);
//localhost:8000/auth/facebook/callbackにGETアクセスした時に処理が行われる設定
app.get('/auth/facebook/callback',
//処理が失敗した時のリダイレクト先の設定
passport.authenticate('facebook', {failureRedirect: '/login' }),
function(req, res) {
//処理が成功した時のリダイレクト先の設定
res.redirect('/');
});
//localhost:8000/loginにアクセスした時にloginRouter処理がなされる設定
app.get('/login', loginRouter);
//localhost:8000/logoutにアクセスした時にlogoutRouter処理がなされる設定
app.get('/logout', logoutRouter);
//404エラーの処理設定
app.use(function(req, res, next) {
next(createError(404));
});
// エラー処理の設定
app.use(function(err, req, res, next) {
// ローカル環境のみ表示されるエラーの設定
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// エラーページを表示する設定
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
var FACEBOOK_APP_ID = '4492xxxxxxxx';
は、先ほど作成した、アプリIDとapp secretをそれぞれ代入します。
var FACEBOOK_APP_SECRET = '170dde4751f2exxxxxxxxxx';
続いて、login.jsとlogout.js、そしてindex.jsに記述していきます。
'use strict';
//expressの読み込み
var express = require('express');
//expressでルーターを使う設定
var router = express.Router();
//localhost:8000/loginにアクセスした際に、login.pugがレンダリングされる処理
router.get('/login', function(req, res) {
res.render('login');
});
//モジュールのエキスポート
module.exports = router;
'use strict';
//expressの読み込み
var express = require('express');
//expressでルーターを使う設定
var router = express.Router();
//localhost:8000/logoutにアクセスした際に、ログアウトされ、
//localhost:8000/にリダイレクトされる処理
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
//モジュールのエキスポート
module.exports = router;
'use strict';
var express = require('express');
var router = express.Router();
//localhost:8000/にアクセスした際に、index.pugがレンダリングされ、
//index.pug内でtitleとuserが使えるようになる処理
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express', user: req.user });
});
module.exports = router;
これでモジュールの処理設定が完了しました。
続いて画面の設定です。
上の処理に合わせて、画面設定をしていきます。
extends layout
block content
h1= title
p Welcome to #{title}
if user
p Hello, #{user.displayName}
a(href="/logout") Logout
else
a(href="/login") Login
#{title}
にはindex.jsで渡した、'Express'という文字が入り、
{user.displayName}
のuser
には、req.userが入ります。
req.userは、app.js
のStarategy設定でdisplayName
をプロフィールから受け取れるようにしたので、displayName
が利用できます。
extends layout
block content
a(href="/auth/facebook") Login with Facebook
ログインするための
a(href="/auth/facebook")
を追加しました。
ログインとログアウトをしてみる
これで処理か完成しました。コンソールにて以下のコマンドを入力し、
PORT=8000 npm start
以下のURLにアクセスしてみてください。
http://localhost:8000/
すると、/login
に移動するので、Login with Facebook
をクリックします。
すると、ログイン画面に出るので、
続いて、自分のFacebookアカウントでログインボタンをクリックし、ログインします。
ログインすると、以上のように、Hello 自分の名前
と表示されます。
続いて、Logout
をクリックし、ログアウトできるかの確認も行います。
無事、最初のログイン画面に移動できたら、ログアウトの完了です。
お疲れ様でした。
おまけ
認証された人しか見れないようにするには、app.jsに以下のように書き込みます。
//認証者を確かめる関数
function authenticatedUser(req, res, next) {
//認証されている人は次の処理が実行される。
if (req.isAuthenticated()) { return next(); }
//認証されてない人は`/login`にリダイレクトされる。
res.redirect('/login');
}
/users
を認証者だけが見えるように設定。
app.use('/users', authenticatedUser, usersRouter);