Node.js の express コマンドで、アプリケーションを自動生成した後、ログイン/ログアウトを管理する機能について学んだ時のメモです。 O'REILLY Nodeクックブックを参考に実装しようとしたら、書籍が書かれた時期と現在利用しているバージョンが異なるため、とっても苦心したので、忘れない様にメモです。
express コマンドでのアプリの生成
テンプレートエンジンは、デフォルトのJADEを利用し、CSSプロプロセッサは、stylus を利用してアプリの雛形を作成します。
$ express --css stylus myapp2
create : myapp2
create : myapp2/package.json
create : myapp2/app.js
create : myapp2/public
create : myapp2/public/javascripts
create : myapp2/public/images
create : myapp2/public/stylesheets
create : myapp2/public/stylesheets/style.styl
create : myapp2/routes
create : myapp2/routes/index.js
create : myapp2/routes/users.js
create : myapp2/views
create : myapp2/views/index.jade
create : myapp2/views/layout.jade
create : myapp2/views/error.jade
create : myapp2/bin
create : myapp2/bin/www
install dependencies:
$ cd myapp2 && npm install
run the app:
$ DEBUG=myapp2:* npm start
フォント色とバックグランド色の変更
本題からそれるのですが、CSSプリプロセッサのソースを変更して、フォント色とバックグランド色を変更します。
body
padding: 50px
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif
color: white <<-- 追加
background-color: #26343F <<-- 追加
a
color: #00B7FF
セッション管理のミドルウェアの作成
このExpress で開発したウェブ・サイト全体のセッションを管理して、ログインしない者に中身を見せない様にするためのミドルウェアを作ります。 そして、app.js に設定して、アクセスの際にログイン管理のミドルウェアを通過する様にします。
まずは、ミドルウェア部分の実装です。
var users = { 'tkr': 'password' }; // ユーザーパスワード
module.exports = function(req, res, next) {
var method = req.method.toLowerCase();
var user = req.body;
var logout = (method === 'post' && req.url === '/logout');
var login = (method === 'post' && user);
// ログアウト
if (logout) {
delete req.session.user;
}
// ログイン
if (login) {
Object.keys(users).forEach(function(name) {
if (user.name === name && user.pwd === users[name]) {
req.session.user = {
name: user.name,
pwd: user.pwd
};
}
});
}
// セッションが無ければ ログイン画面へ
if (!req.session.user) {req.url = '/'}
next();
}
参考にした O'REILLY Nodeクックブック p200 のサンプルコードから、結構多くの変更があります。 HTTP DELETE はブラウザによって、動作しなかったので、HTTP POST を利用する様に変更しました。 それから、廃止された機能を削ってあります。 ユーザーとパスワードは、このコードにベタ書きしていますが、実際はデータベースに保管する必要があります。また、パスワードもクリアテキストで保管するのではなく、ハッシュにして保存し、照合はハッシュで実施する事で、パスワードを知られない様にする必要があります。 ここでは本題では無いので、簡単にコードに留めます。
ユーザー認証が成功すると req.session.user に保管します。
次に、Expressアプリケーションの本体である app.js に変更を加えます。
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser'); // ここもexpress の一部から、独立に変更されている
var session = require('express-session'); // <<-- 追加 後に対応するnpm install を実行する
var routes = require('./routes/index');
var users = require('./routes/users');
参考にした O'REILLY Nodeクックブック p196では、express コマンドに --session オプションを付与して自動的にモジュールを追加との解説がありますが、node.js v4.x系、v6.x系の express コマンドからは、このオプションが廃止されています。 それから、express.session()がexpressの一部から、別のモジュールに独立した様ですから、この辺の実装が変わります。
次のコードも、同じくapp.jsの変更部分ですが、先ほど追加した login.js をミドルウェアとして設定する部分になります。
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
// ここから追加
key = {
secret: 'zakuzaku',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 180000
}
};
app.use(session(key));
//
app.use(require('./login'));
app.use('/', routes);
app.use('/logout', routes);
app.use('/users', users);
// ここまで
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// 任意のページもログイン対象にする 追加
app.use('/:page', routes);
// error handlers
app.use(session(key))は、セッションを追跡するための設定で、この設定ではオンメモリとなっていますので、スケール・アウトする場合には、KVSに保存する必要があります。
- app.use(require('./login')) のルーティング部分は、loginモジュールを通過させる事で、ログインしていないユーザーにコンテンツを参照できなくします。
- app.use('/', routes) は、express がデフォルトで組み込むルーティングですが、routes.js と index.jade を変更する事で、/ をアクセスする場合、未ログインの場合は、ログインをページを表示し、ログイン済みの場合は、挨拶文を表示します。
- app.use('/logout', routes)は、ログアウト処理のルーティングです。 このURLをアクセスするとログイン情報を削除する事でログアウトします。
- app.use('/users', users)は、express がデフォルトで設定したルーティングです。ログインしなければ、/usersをアクセスできなくなります。
- // catch 404 から始るコードを、ここに挟む事で、ログイン後に、該当ページが存在しない場合、404 Not Found を表示します。 また、未ログインの場合は、ログイン・ページを表示して、内部構造を推定させません。
- app.use('/:page', routes) は、/ 以下の任意のページアクセスも、routes.js モジュールへルーティンします。
URLルートのコード変更
app.js から URLルーティングによって呼び出されるコード index.js です。 app.js の中で、app.use で定義する事で、HTTP メソッドに関わらず該当のURLルートのアクセスが、このコードへ飛んできます。 このため、post と get の処理をそれぞれ書いておく必要があります。 app.js の中で、app.get や app.post でモジュール内の特定のメソッドに飛ばすこともできますが、app.use を利用することで、app.js をシンプルに保つ事が可能になります。
var express = require('express');
var router = express.Router();
function render(req, res, next) {
res.render('index', { title: 'Express', user: req.session.user });
}
router.get('/', function(req, res, next) {
render(req, res, next);
});
router.post('/', function(req, res, next) {
render(req, res, next);
});
module.exports = router;
JADE テンプレートの変更と追加
expressコマンドで生成される index.jade の最終行に include login.jade を追加します
extends layout
block content
h1= title
p Welcome to #{title}
include login.jade
ユーザーがログインしている際は「こんにちは」表示して、未ログイン状態では、ログインのフォームを表示します。
if user
form(method='post', action='/logout')
input(name='logout', type='hidden', value='DELETE')
p #{user.name}さん、こんにちは!
a(href='javascript:', onClick='forms[0].submit()') [ログアウト]
else
p ログインしてください
form(method='post', action='/')
fieldset
legend ログイン
p
label(for='name') ユーザー名:
input(name='name')
p
label(for='pwd') パスワード:
input(type='password', name='pwd')
input(type='submit')
モジュールのインストールとアプリ起動
express-session が独立のモジュールになっているため、追加でインストールします。また、package.jsonに書き込みます。 package.json に登録された残りのモジュールをすべてインストールするために、npm install を実行します。
myapp2$ npm install --save express-session
myapp2$ npm install
次に、アプリを起動します。
myapp2$ npm start
> myapp2@0.0.0 start /home/tkr/express_work2/myapp2
> node ./bin/www
GET /favicon.ico 200 1145.927 ms - 470
GET / 200 157.050 ms - 470
GET /stylesheets/style.css 200 372.358 ms - 154
実行結果
/users をアクセスした場合の画面、ログインしていない場合は、ログイン画面が表示されます。
以上