質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Redis

Redisは、オープンソースのkey-valueデータストアで、NoSQLに分類されます。すべてのデータをメモリ上に保存するため、処理が極めて高速です。

セッション

Sessionはクライアントがサーバに送ったすべてのリクエストのことを指します。

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

Q&A

0回答

5024閲覧

NodeJS(Express4)+Passportでログイン認証後にセッションIDの再発行を行うには

buibui80

総合スコア1033

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Redis

Redisは、オープンソースのkey-valueデータストアで、NoSQLに分類されます。すべてのデータをメモリ上に保存するため、処理が極めて高速です。

セッション

Sessionはクライアントがサーバに送ったすべてのリクエストのことを指します。

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

0グッド

1クリップ

投稿2015/06/17 03:23

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]

lang

1{ 2 "name": "passport_test", 3 "version": "0.0.0", 4 "private": true, 5 "scripts": { 6 "start": "node ./bin/www" 7 }, 8 "dependencies": { 9 "body-parser": "~1.12.4", 10 "connect-redis": "~2.3.0", 11 "cookie-parser": "~1.3.5", 12 "csurf": "~1.8.3", 13 "debug": "~2.2.0", 14 "ejs": "~2.3.1", 15 "express": "~4.12.4", 16 "express-generator": "~4.12.4", 17 "express-session": "~1.11.3", 18 "method-override": "~2.3.3", 19 "morgan": "~1.5.3", 20 "multer": "~0.1.8", 21 "passport": "~0.2.2", 22 "passport-local": "~1.0.0", 23 "serve-favicon": "~2.2.1", 24 "redis": "~0.12.1", 25 "connect-flash": "~0.1.1", 26 "bcrypt": "~0.8.3" 27 }, 28 "devDependencies": { 29 "nodemon": "~1.3.7" 30 } 31}

lang

1// app.js 2var util = require("util"); 3var logger = require('morgan'); 4var favicon = require('serve-favicon'); 5var path = require('path'); 6var methodOverride = require('method-override'); 7var cookieParser = require('cookie-parser'); 8var bodyParser = require('body-parser'); 9var multer = require('multer'); 10var csurf = require('csurf'); 11var bcrypt = require('bcrypt'); 12 13var express = require('express'); 14var session = require('express-session'); 15var flash = require("connect-flash"); 16var RedisStore = require('connect-redis')(session); 17 18var passport = require('passport'); 19var LocalStrategy = require('passport-local').Strategy; 20 21var appConfig = { 22 pathInfo: { 23 favicon : path.join(__dirname, '/public/favicon.ico'), 24 static: { 25 views : path.join(__dirname, 'views'), 26 public : path.join(__dirname, 'public'), 27 } 28 }, 29 storeOption: { // Redis Server 30 host : 'localhost', 31 port : 6379, 32 prefix : 'sess', 33 ttl : 30 34 }, 35 sessionOption: { 36 secret : 'session_secret', 37 resave : true, 38 saveUninitialized : true , 39 store : null, 40 cookie : { 41 httpOnly : true, 42 secure : false, 43 path : '/' 44 } 45 } 46}; 47 48// ダミーデータ 49var users = [ 50 { id: 1, username: 'b', password: 'bb', email: 'bbbb@example.com', provider: 'local' } 51 ,{ id: 2, username: 'c', password: 'cc', email: 'cccc@example.com', provider: 'local' } 52 ,{ id: 3, username: 'a', password: 'aa', email: 'aaaa@example.com', provider: 'local' } 53]; 54 55 56//-------------- 57// custom utils 58 59 60// ダミーデータアクセス用ユーティリティ 61exports = module.exports = UserDataUtils = { 62 63 // ユーザーIDを元にユーザー情報をコールバック 64 findById: function(id, fn) 65 { 66 var idx = id - 1; 67 if (users[idx]) 68 { 69 fn(null, users[idx]); 70 } 71 else 72 { 73 fn(new Error('User ' + id + ' does not exist')); 74 } 75 }, 76 77 // ユーザー名を元にユーザー情報をコールバック 78 // provider: local, twitter, etc. 79 findByUsername: function(provider, obj, fn) 80 { 81 for (var i = 0, len = users.length; i < len; i++) 82 { 83 var user = users[i]; 84 switch(provider) 85 { 86 case "local": 87 if (user.username === obj) { return fn(null, user); } 88 break; 89 case "twitter": 90 if (user.profile_id === obj.profile.id) { return fn(null, user); } 91 break; 92 default: 93 } 94 } 95 return fn(null, null); 96 } 97}; 98 99 100// Passport管理用ユーティリティ 101exports = module.exports = PassportUtils = { 102 103 ensureAuthenticated: function (req, res, next) 104 { 105 if (!req.isAuthenticated()) { return res.redirect('/'); } 106 next(); 107 }, 108 109 serializeUser: function(user, done) { 110 console.log("[passport] [serializeUser]", user); 111 done(null, user.id); 112 }, 113 114 deserializeUser: function(id, done) { 115 console.log("[passport] [deserializeUser]", id); 116 process.nextTick(function(){ 117 118 // data access 119 UserDataUtils.findById(id, function (err, user) { 120 done(err, user); 121 }); 122 123 }); 124 }, 125 126 localStrategy: function(username, password, done) { 127 process.nextTick(function(){ 128 UserDataUtils.findByUsername("local", username, function(err, user) { 129 if (err) 130 { 131 console.log("[passport] [4]", username, password); 132 return done(err); 133 } 134 if (!user) 135 { 136 console.log("[passport] [3]", username, password); 137 return done(null, false, { message: username + 'は存在しないユーザーです' }); 138 } 139 if (user.password != password) 140 { 141 console.log("[passport] [2]", username, password); 142 return done(null, false, { message: 'パスワードに誤りがあります' }); 143 } 144 console.log("[passport] [1]", username, password); 145 return done(null, user); 146 }); 147 }); 148 } 149}; 150 151 152 153// app 154var app = express(); 155// set NODE_ENV=xxxxxxx; npm start; 156var node_env = app.get('env'); 157 158app.set('views', appConfig.pathInfo.static.views ); 159app.set('view engine', 'ejs'); 160 161//app.use(favicon(appConfig.pathInfo.favicon)); 162app.use(logger('dev')); 163app.use(methodOverride()); 164 165app.use(cookieParser()); 166app.use(function(req, res, next){ 167 appConfig.sessionOption.store = new RedisStore(appConfig.storeOption); 168 session(appConfig.sessionOption)(req, res, next); 169}); 170 171app.use(bodyParser.json()); 172app.use(bodyParser.urlencoded({ extended: true })); 173app.use(multer()); 174app.use(flash()); 175//app.use(csurf()); 176 177app.use(express.static( appConfig.pathInfo.static.public )); 178 179 180// passport 181passport.serializeUser(PassportUtils.serializeUser); 182passport.deserializeUser(PassportUtils.deserializeUser); 183passport.use(new LocalStrategy({usernameField: 'username', passwordField: 'password'}, PassportUtils.localStrategy)); 184app.use(passport.initialize()); 185app.use(passport.session()); 186 187 188// routes 189app.get('/logout', function(req, res){ 190 req.logout(); 191 req.flash('message', "ログアウトしました"); 192 res.redirect('/'); 193}); 194 195app.get('/', function(req, res){ 196 res.render('login', { 197 user : req.user, 198 message : req.flash('message') 199 }); 200}); 201 202app.post('/login', function(req, res, next) { 203 passport.authenticate('local', function(err, user, info) { 204 console.log("[post] [login]", err, user, info); 205 if (err) { return next(err); } 206 if (!user) 207 { 208 req.flash('message', info.message); 209 return res.redirect('/'); 210 } 211 req.logIn(user, function(err2) { 212 if (err2) { return next(err2); } 213 req.flash('message', "ログインしました"); 214 215 // **************************************** 216 // セッションIDを再発行する場合 217 //console.log("[regenerate] [before]", util.inspect(req.session.id)); 218 //console.log("[regenerate] [before]", util.inspect(req.cookies["connect.sid"])); 219 //req.session.regenerate(function(err3) { 220 // console.log("[regenerate] [after]", util.inspect(req.session.id)); 221 // console.log("[regenerate] [after]", util.inspect(req.cookies["connect.sid"])); 222 // 223 // return res.redirect('/account'); 224 //}); 225 226 // **************************************** 227 // セッションIDを再発行しない場合 228 return res.redirect('/account'); 229 230 }); 231 })(req, res, next); 232}); 233 234app.get('/account', PassportUtils.ensureAuthenticated, function(req, res){ 235 res.render('account', { 236 user : req.user, 237 message : req.flash('message') 238 }); 239}); 240 241// catch 404 and forward to error handler 242app.use(function(req, res, next) { 243 var err = new Error('Not Found'); 244 err.status = 404; 245 next(err); 246}); 247 248// error handlers 249app.use(function(err, req, res, next) { 250 res.status(err.status || 500); 251 res.render('error', { 252 message : err.message, 253 error : err 254 }); 255}); 256 257module.exports = app;

lang

1<!-- views/login.ejs --> 2<!DOCTYPE html> 3<html> 4<head> 5</head> 6<body> 7 <h1>Login</h1> 8 <h3><%= message %></h3> 9 <!-- submit to /login --> 10 <form action="/login" method="post"> 11 <input type="text" id="username" name="username" value="a"> 12 <input type="password" id="password" name="password" value="aa"> 13 <button type="submit">Submit</button> 14 </form> 15</body> 16</html>

lang

1<!-- views/account.ejs --> 2<!DOCTYPE html> 3<html> 4<head> 5</head> 6<body> 7 <h1>Account</h1> 8 <h3><%= message %></h3> 9 <a href="/logout">Logout</a> | 10 <a href="/account">account</a> | 11 <h3><%= user.id %></h3> 12 <h3><%= user.username %></h3> 13 <h3><%= user.password %></h3> 14 <h3><%= user.email %></h3> 15</body> 16</html>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問