NodeJS(Express4)+Passportでログイン認証後にセッションIDの再発行を行うには
受付中
回答 0
投稿
- 評価
- クリップ 1
- VIEW 3,889
Node.JS(Express4)+Passportのログイン認証後において、
ログイン処理時にセッションIDの再発行を行うにはどのようにすれば良いでしょうか?
app.post('/login', function(req, res, next) 内の
req.logIn にて req.session.regenerate を行いセッションIDの再発行を行うものの、
Cookieのconnect.sidが更新されずにセッションIDとの不一致の為にセッション切れを起こしてしまいます。
req.session.regenerate で行うものと思っていましたが違う手段があるのでしょうか?
※セッションIDの再発行箇所をコメントアウトしているので、
セッション切れを確認するにはコメントアウトを切り替えてご確認ください。
どうぞよろしくお願い致します。
セッション管理用DBに Redis を使用しているので、Redisを起動した状態で確認をお願いします。
Redis含めた設定は app.js の appConfig に指定しています。
(当方ではRedis 3.0.2を使用しています)
※セッションの有効期限は appConfig.storeOption.ttl に秒指定しています。
[package.json]
ログイン処理時にセッションIDの再発行を行うにはどのようにすれば良いでしょうか?
app.post('/login', function(req, res, next) 内の
req.logIn にて req.session.regenerate を行いセッションIDの再発行を行うものの、
Cookieのconnect.sidが更新されずにセッションIDとの不一致の為にセッション切れを起こしてしまいます。
req.session.regenerate で行うものと思っていましたが違う手段があるのでしょうか?
※セッションIDの再発行箇所をコメントアウトしているので、
セッション切れを確認するにはコメントアウトを切り替えてご確認ください。
どうぞよろしくお願い致します。
セッション管理用DBに Redis を使用しているので、Redisを起動した状態で確認をお願いします。
Redis含めた設定は app.js の appConfig に指定しています。
(当方ではRedis 3.0.2を使用しています)
※セッションの有効期限は appConfig.storeOption.ttl に秒指定しています。
[package.json]
{
"name": "passport_test",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "~1.12.4",
"connect-redis": "~2.3.0",
"cookie-parser": "~1.3.5",
"csurf": "~1.8.3",
"debug": "~2.2.0",
"ejs": "~2.3.1",
"express": "~4.12.4",
"express-generator": "~4.12.4",
"express-session": "~1.11.3",
"method-override": "~2.3.3",
"morgan": "~1.5.3",
"multer": "~0.1.8",
"passport": "~0.2.2",
"passport-local": "~1.0.0",
"serve-favicon": "~2.2.1",
"redis": "~0.12.1",
"connect-flash": "~0.1.1",
"bcrypt": "~0.8.3"
},
"devDependencies": {
"nodemon": "~1.3.7"
}
}
// app.js
var util = require("util");
var logger = require('morgan');
var favicon = require('serve-favicon');
var path = require('path');
var methodOverride = require('method-override');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var multer = require('multer');
var csurf = require('csurf');
var bcrypt = require('bcrypt');
var express = require('express');
var session = require('express-session');
var flash = require("connect-flash");
var RedisStore = require('connect-redis')(session);
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var appConfig = {
pathInfo: {
favicon : path.join(__dirname, '/public/favicon.ico'),
static: {
views : path.join(__dirname, 'views'),
public : path.join(__dirname, 'public'),
}
},
storeOption: { // Redis Server
host : 'localhost',
port : 6379,
prefix : 'sess',
ttl : 30
},
sessionOption: {
secret : 'session_secret',
resave : true,
saveUninitialized : true ,
store : null,
cookie : {
httpOnly : true,
secure : false,
path : '/'
}
}
};
// ダミーデータ
var users = [
{ id: 1, username: 'b', password: 'bb', email: 'bbbb@example.com', provider: 'local' }
,{ id: 2, username: 'c', password: 'cc', email: 'cccc@example.com', provider: 'local' }
,{ id: 3, username: 'a', password: 'aa', email: 'aaaa@example.com', provider: 'local' }
];
//--------------
// custom utils
// ダミーデータアクセス用ユーティリティ
exports = module.exports = UserDataUtils = {
// ユーザーIDを元にユーザー情報をコールバック
findById: function(id, fn)
{
var idx = id - 1;
if (users[idx])
{
fn(null, users[idx]);
}
else
{
fn(new Error('User ' + id + ' does not exist'));
}
},
// ユーザー名を元にユーザー情報をコールバック
// provider: local, twitter, etc.
findByUsername: function(provider, obj, fn)
{
for (var i = 0, len = users.length; i < len; i++)
{
var user = users[i];
switch(provider)
{
case "local":
if (user.username === obj) { return fn(null, user); }
break;
case "twitter":
if (user.profile_id === obj.profile.id) { return fn(null, user); }
break;
default:
}
}
return fn(null, null);
}
};
// Passport管理用ユーティリティ
exports = module.exports = PassportUtils = {
ensureAuthenticated: function (req, res, next)
{
if (!req.isAuthenticated()) { return res.redirect('/'); }
next();
},
serializeUser: function(user, done) {
console.log("[passport] [serializeUser]", user);
done(null, user.id);
},
deserializeUser: function(id, done) {
console.log("[passport] [deserializeUser]", id);
process.nextTick(function(){
// data access
UserDataUtils.findById(id, function (err, user) {
done(err, user);
});
});
},
localStrategy: function(username, password, done) {
process.nextTick(function(){
UserDataUtils.findByUsername("local", username, function(err, user) {
if (err)
{
console.log("[passport] [4]", username, password);
return done(err);
}
if (!user)
{
console.log("[passport] [3]", username, password);
return done(null, false, { message: username + 'は存在しないユーザーです' });
}
if (user.password != password)
{
console.log("[passport] [2]", username, password);
return done(null, false, { message: 'パスワードに誤りがあります' });
}
console.log("[passport] [1]", username, password);
return done(null, user);
});
});
}
};
// app
var app = express();
// set NODE_ENV=xxxxxxx; npm start;
var node_env = app.get('env');
app.set('views', appConfig.pathInfo.static.views );
app.set('view engine', 'ejs');
//app.use(favicon(appConfig.pathInfo.favicon));
app.use(logger('dev'));
app.use(methodOverride());
app.use(cookieParser());
app.use(function(req, res, next){
appConfig.sessionOption.store = new RedisStore(appConfig.storeOption);
session(appConfig.sessionOption)(req, res, next);
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(multer());
app.use(flash());
//app.use(csurf());
app.use(express.static( appConfig.pathInfo.static.public ));
// passport
passport.serializeUser(PassportUtils.serializeUser);
passport.deserializeUser(PassportUtils.deserializeUser);
passport.use(new LocalStrategy({usernameField: 'username', passwordField: 'password'}, PassportUtils.localStrategy));
app.use(passport.initialize());
app.use(passport.session());
// routes
app.get('/logout', function(req, res){
req.logout();
req.flash('message', "ログアウトしました");
res.redirect('/');
});
app.get('/', function(req, res){
res.render('login', {
user : req.user,
message : req.flash('message')
});
});
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
console.log("[post] [login]", err, user, info);
if (err) { return next(err); }
if (!user)
{
req.flash('message', info.message);
return res.redirect('/');
}
req.logIn(user, function(err2) {
if (err2) { return next(err2); }
req.flash('message', "ログインしました");
// ****************************************
// セッションIDを再発行する場合
//console.log("[regenerate] [before]", util.inspect(req.session.id));
//console.log("[regenerate] [before]", util.inspect(req.cookies["connect.sid"]));
//req.session.regenerate(function(err3) {
// console.log("[regenerate] [after]", util.inspect(req.session.id));
// console.log("[regenerate] [after]", util.inspect(req.cookies["connect.sid"]));
//
// return res.redirect('/account');
//});
// ****************************************
// セッションIDを再発行しない場合
return res.redirect('/account');
});
})(req, res, next);
});
app.get('/account', PassportUtils.ensureAuthenticated, function(req, res){
res.render('account', {
user : req.user,
message : req.flash('message')
});
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message : err.message,
error : err
});
});
module.exports = app;
<!-- views/login.ejs -->
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Login</h1>
<h3><%= message %></h3>
<!-- submit to /login -->
<form action="/login" method="post">
<input type="text" id="username" name="username" value="a">
<input type="password" id="password" name="password" value="aa">
<button type="submit">Submit</button>
</form>
</body>
</html>
<!-- views/account.ejs -->
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Account</h1>
<h3><%= message %></h3>
<a href="/logout">Logout</a> |
<a href="/account">account</a> |
<h3><%= user.id %></h3>
<h3><%= user.username %></h3>
<h3><%= user.password %></h3>
<h3><%= user.email %></h3>
</body>
</html>
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
まだ回答がついていません
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.22%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる