반응형
Express-mysql-session으로 여권 deserializeUser가 실행되지 않도록 방지
facebook을 통해 사용자를 로그인하기 위해 passport.js를 사용하는 앱이 있으며, 로그인 상태를 유지하기 위해 express-mysql-session을 사용하려고합니다. express-mysql-session 코드를 포함하지 않으면 passport serializeUser 및 deserializeUser 함수가 정상적으로 작동합니다. 맞지 않고 사용자가 제대로 로그인되지 않습니다.
server.js 파일
var express = require('express');
var mysql = require('mysql');
var passport = require('passport');
var session = require('express-session');
var MySQLStore = require('express-mysql-session')(session);
if (typeof process.env.OPENSHIFT_MYSQL_DB_HOST === "undefined"){
var options = {
host : 'localhost',
port : '3307',
user : 'user',
password : 'password',
database : 'database',
socketpath: '/var/run/mysqld/mysqld.sock'
}
} else {
var options = {
host : process.env.OPENSHIFT_MYSQL_DB_HOST,
port : process.env.OPENSHIFT_MYSQL_DB_PORT,
user : process.env.OPENSHIFT_MYSQL_DB_USERNAME,
password : process.env.OPENSHIFT_MYSQL_DB_PASSWORD,
database : process.env.OPENSHIFT_APP_NAME,
socket : process.env.OPENSHIFT_MYSQL_DB_SOCKET
}
};
var connection = mysql.createConnection(options);
var sessionStore = new MySQLStore({
checkExpirationInterval: 900000,// How frequently expired sessions will be cleared; milliseconds.
expiration: 86400000,// The maximum age of a valid session; milliseconds.
createDatabaseTable: false,// Whether or not to create the sessions database table, if one does not already exist.
connectionLimit: 1,
schema: {
tableName: 'LoginRequests',
columnNames: {
session_id: 'loginID',
expires: 'expires',
data:'data'
}
}
}, connection);
self.initializeServer = function() {
self.app = module.exports = express();
self.app.configure(function() {
self.app.set('views', __dirname + '/public');
self.app.set('view engine', 'html');
self.app.engine('html', require('hogan-express'));
self.app.enable('view cache');
self.app.use(express.favicon());
self.app.use(express.logger('dev'));
self.app.use(express.bodyParser());
self.app.use(express.methodOverride());
self.app.use(express.cookieParser('secret'));
self.app.use(session({
key: 'session_cookie_name',
secret: 'secret',
cookie: {maxAge: 3600000, secure:false},
store: sessionStore,
resave: false,
saveUninitialized: false
}));
// required for passport
self.app.use(passport.initialize());
self.app.use(passport.session()); // persistent login sessions
self.app.use(express.static(path.join(__dirname, 'public')));
self.app.use('/public',express.static(__dirname, '/public'));
self.app.use(self.app.router);
//self.app.use(require('stylus').middleware(__dirname + '/public'));
});
require('./routes/site.js');
require('./config/passport.js')(passport); // pass passport for configuration
}
따라서 위의 세션 개체에서 "저장"옵션을 주석 처리하면 여권 기능이 적중됩니다. 이 줄을 주석 처리하지 않으면 deserializeUser 함수가 적중되지 않습니다.
여권 기능
passport.serializeUser(function(user, done) {
console.log('you have been serialized!');
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
console.log('you have been deserialized!');
connection.query("SELECT * FROM Users WHERE id = "+id,function(err,rows){
done(err, rows[0]);
});
});
편집하다
Mor Paz는 디버그 모듈로 서버를 실행할 때의 일부 로그를 포함 할 것을 제안했습니다. 다음은 사용자가 직렬화되기 직전과 직후의 로그입니다. 사용자는이 근처의 어느 시점에서 역 직렬화되어야하지만 결코 그렇지 않습니다.
GET /auth/facebook 302 81ms - 412b
express-mysql-session:log Getting session: oNcJ4UapxCY_zKOyfSBTUWaVhaNZuFRq +356ms
you are a user!
you have been serialized!
express-mysql-session:log Setting session: tgRPY-Mb1VDP2zaSMOFhlf_IWFhVpTia +798ms
express-mysql-session:log Getting session: tgRPY-Mb1VDP2zaSMOFhlf_IWFhVpTia +6ms
GET /auth/facebook/callback? code=AQCWPvA5ZRMYoTueW6_wWU49Up5ggjW68ufOtiYkU5IzhRjSNyyWnzlQVprgQo_uubQkEVvNI0yo53ET3cWBnDAHUGmAXPBy_ITEmC-biE2KEGEr0iCm_cqjuG90nnePY-k9U2oFUbX2kvLgMeM0kZ-094EHiU_NJjmAJNj6mzTkSE47935RhJy0Tba_sYS88_C0N3kn5f5kcoTC4KsgW1gBHWWJAwZ68Lj94ffVe2hN97580CtzEpJa0wwQHwTBYfmjQ0NfUdx07m4rXW9R7PR06aHDcUDrYqR9Kb0LWq4sZLbQjV5rI7gzkWG-huhq7IY 302 825ms - 72b
express-mysql-session:log Setting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +56ms
express-mysql-session:log Getting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +23ms
express-mysql-session:log Getting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +2ms
GET /profile 200 84ms - 4.22kb
문제를 재현 할 수 없었기 때문에 실례를 준비했습니다. [Github 저장소]
환경 변수 의 사용을 보았 기 때문에 Openshift 용으로 제작되었습니다 (다른 사용 사례에 쉽게 적용 할 수 있음).
원래 개념을 약간 수정했습니다.
- 더 이상 사용되지 않는 (익스프레스) 번들 미들웨어 사용을 대체했습니다.
- 개념 대신 클래스 사용
self = this - 사용자 로그인 에 Facebook 대신 Github 사용 ...
- DB에 새로운 사용자를 포함하는 몇 가지 기본 기능 포함
- 일부 원본 모듈 누락 (쉽게 포함 할 수 있음)
출발점으로 도움이 되길 바랍니다.
// .: DB Configuration :.
const mysql = require('mysql');
var dbconf = {host:process.env.OPENSHIFT_MYSQL_DB_HOST,port:process.env.OPENSHIFT_MYSQL_DB_PORT,user:process.env.OPENSHIFT_MYSQL_DB_USERNAME,password:process.env.OPENSHIFT_MYSQL_DB_PASSWORD,database:process.env.OPENSHIFT_APP_NAME,socket:process.env.OPENSHIFT_MYSQL_DB_SOCKET}}
const dbconn = mysql.createConnection(dbconf); /*or create a pool*/ dbconn.connect();
// .: Express & Other Middleware Modules :.
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var cookieParser = require('cookie-parser');
var serveStatic = require('serve-static');
// .: Sessions :.
var passport = require('passport');
var GitHubStrategy = require('passport-github2');
var session = require('express-session');
var MySQLStore = require('express-mysql-session')(session);
var sessionStoreConf = {
connectionLimit:1,checkExpirationInterval:900000,expiration:86400000,
createDatabaseTable:true,schema:{tableName:'LoginRequests',columnNames:{session_id:'loginID',expires:'expires',data:'data'}}
};
var sessionStore = new MySQLStore(sessionStoreConf,dbconn);
// .: Server (class) :.
class Server {
constructor(port, ip){
this.app = express();
this.app.use(cookieParser('secret'));
this.app.use(session({
key:'session_cookie_name',
secret:'secret',
cookie:{maxAge:3600000,secure:false},
store: sessionStore,
resave:false,
saveUninitialized:false
}));
this.app.use(passport.initialize());
this.app.use(passport.session());
this.app.use(serveStatic(path.join(__dirname,'public')))
this.app.listen(port,ip,function(){console.log('[i] Application worker started.');});
//require('./routes/site.js'); //~Example (routes/site.js) :
this.app.get("/",function(req,res){res.send("<a href='./auth/github'>Click here to login (GitHub)</a>");})
this.app.get('/auth/github',passport.authenticate('github',{scope:['user:email']}));
this.app.get('/auth/github/callback',passport.authenticate('github',{failureRedirect:'/'}),function(req,res){res.redirect('/success');});
// route for valid logins
this.app.get('/success', function(req, res){
if(req.user){ console.log(req.user); res.send(req.user); }
else{ res.redirect('/login'); }
});
// route to check the sessionStore table entries in the browser
this.app.get('/sessions',function(req,res){
dbconn.query("SELECT * FROM LoginRequests",function(err,rows){
if(err){console.log(err);}else{
if(rows.length!=0){
res.send(JSON.stringify(rows));
console.log(rows);
}else{res.send("No LoginRequests found");}
}
});
});
//require('./config/passport.js')(passport); //~Example (config/passport.js) :
passport.use(new GitHubStrategy(
{clientID:"clientID",clientSecret:"clientSecret",callbackURL:"callbackURL"},
function(token, tokenSecret, user, cb){CheckUser('github',user,cb);}
));
}
}
const server = new Server(process.env.OPENSHIFT_NODEJS_PORT,process.env.OPENSHIFT_NODEJS_IP);
// .: Passport : Serialize & Deserialize User :.
passport.serializeUser(function(user, done){
console.log('[passport] serializeUser');
done(null,user.id);
});
passport.deserializeUser(function(id, done) {
console.log('[passport] deserializeUser');
dbconn.query("SELECT * FROM Users WHERE id=?",[id],function(err,rows){
if(err){console.log(err);}else{
if(rows.length!=0){ done(err,rows[0]); }
else{ done(err,null); }
}
});
});
//:Check if user exists:
function CheckUser(platform,user,cb){
dbconn.query("SELECT * FROM Users WHERE id=?",[user.id],function(err,rows){
if(err){console.log(err); cb(err,null);}else{
if(rows.length!=0){cb(null,user);}
else{CreateUser(platform,user,cb);}
}
});
}
//:Create new user:
function CreateUser(platform,user,cb){
switch(platform){
case "github":
var newUserObj = {id:user.id,platform:platform,email:user.emails[0].value};
dbconn.query("INSERT INTO Users SET ?",newUserObj,function(err){
if(err){console.log(err); cb(err,null);}else{cb(null,user);}
});
break;
default: console.log("[error] (createUser) : platform not implemented :",platform); cb(err,null); break;
}
}
반응형
'Program Club' 카테고리의 다른 글
| TLB 슛 다운이란 무엇입니까? (0) | 2020.11.16 |
|---|---|
| HW kbd 키보드 포커스 iOS로 설정하지 못했습니다 (null). (0) | 2020.11.15 |
| Pycharm에서 docker-compose를 통해 Python 콘솔 실행 (0) | 2020.11.15 |
| iframe에서 IE 11 자사 세션 쿠키가 손실 됨 (0) | 2020.11.15 |
| 클래스 탐색기없이 속성 맵에 속성을 추가하는 방법은 무엇입니까? (0) | 2020.11.15 |