我正在使用passport
,express-session
和connect-pg-simple
。
问题在于会话无法从存储正确获取,并且正确地(我希望,但怀疑)保存。
我的设置是相同的,就像许多教程一样,我找到了。
server.js:
import express from 'express';
import next from 'next';
import bodyParser from 'body-parser';
import session from 'express-session';
import connectPgSimple from 'connect-pg-simple';
const sessionStorage = connectPgSimple(session);
import initAuthentication from '!/server/authentication';
const dev = process.env.NODE_ENV !== 'production'; // eslint-disable-line
const port = process.env.PORT || 3000; // eslint-disable-line
const app = next({ dev });
app.prepare()
.then(() => {
const server = express();
server.use(express.static('public'));
/* Note Since version 1.5.0, the cookie-parser middleware no longer needs
to be used for this module to work. This module now directly reads and writes
cookies on req/res. Using cookie-parser may result in issues
if the secret is not the same between this module and cookie-parser.
https://www.npmjs.com/package/express-session */
// server.use(cookieParser());
server.use(bodyParser.json()); // for parsing application/json
server.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
server.use(session({
secret: 'keyboard cat',
store: new sessionStorage(),
resave: false,
saveUninitialized: false,
cookie: {
secure: false,
maxAge: 30 * 24 * 60 * 60 * 1000
}})
);
initAuthentication(server);
});
authentication.js:
import passport from 'passport';
import LocalStrategy from 'passport-local';
import bcrypt from 'bcrypt';
import {User} from '!/server/db';
import util from 'util';
User.prototype.validPassword = function(password) {
return bcrypt.compareSync(password, this.passwordHash);
};
User.authenticate = (username, password, done) => {
User.findOne({where: {nickname: username}}).then(user => {
if (!user) {
return done(null, false, { message: 'Неверное имя пользователя.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Неверный пароль.' });
}
return done(null, user);
}).catch(err => {
return done(err);
});
};
export default function initAuthentication(server) {
server.use(passport.initialize());
server.use(passport.session());
passport.use('local-signIn', new LocalStrategy(User.authenticate));
passport.serializeUser((user, done) => {
console.log('> serializeUser "'+user.nickname+'" ('+user.id+')');
done(null, user.id);
});
passport.deserializeUser((id, done) => {
console.log('> deserializeUser with id: ' + id)
User.findById(id).then(user => {
done(null, user);
}).catch(error => {
console.log('Error in passport.deserializeUser: ' + error);
done(error, null);
});
});
server.post('/user/login',
passport.authenticate('local-signIn'),
(req, res) => {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
console.log('Authenticated user "'+req.user.nickname+'"');
req.login(req.user, (err)=> {
if (err) console.log(err);
console.log('\t Session established for user "'+req.user.nickname+'"');
res.json(req.user);
});
}
);
function logAuthenticationStatus(req, res, next) {
console.log('Authentication status:')
console.log('\treq.cookies: ' + util.inspect(req.cookies));
console.log('\treq.isAuthenticated: ', req.isAuthenticated());
console.log('\treq.session: ', req.session);
if (req.user) {
console.log('\tLogged in as "'+req.user.nickname+'"');
} else {
console.log('\tNot logged in');
}
next();
}
server.use(logAuthenticationStatus);
server.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
}
有趣的部分是'express-session'的调试输出,这要归功于令人惊讶的npm-package debug。
因此,当/user/login
的请求到达时,使用username = AntonAL,会发生以下情况:
Executing (default): SELECT "id", "nickname", "email", "password", "passwordHash", "lastLoggedIn", "createdAt", "updatedAt" FROM "users" AS "user" WHERE "user"."nickname" = 'AntonAL' LIMIT 1;
> serializeUser "AntonAL" (1)
Authenticated user "AntonAL"
> serializeUser "AntonAL" (1)
Session established for user "AntonAL"
express-session saving qiQfhyAvDDPD7muJLtGdZudKqMug0aAC +23ms
express-session split response +0ms
express-session set-cookie connect.sid=s%3AqiQfhyAvDDPD7muJLtGdZudKqMug0aAC.0wIcunkcEjhaUzs4H7w4uuv6u%2FBKXMROuAm6%2FG0vVQw; Path=/; Expires=Sat, 30 Sep 2017 10:55:31 GMT; HttpOnly +1ms
info: POST /user/login 200 50ms statusCode=200, url=/user/login, host=localhost:3000, content-type=application/json, origin=http://localhost:3000, accept-encoding=gzip, deflate, connection=keep-alive, accept=application/json, user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8, referer=http://localhost:3000/user/login, content-length=44, accept-language=ru, method=POST, httpVersion=1.1, originalUrl=/user/login, , responseTime=50, user=AntonAL
所以,会话保存在db中,让我们检查一下:
SELECT * FROM session WHERE sid='qiQfhyAvDDPD7muJLtGdZudKqMug0aAC';`
sid | sess | expire
----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+---------------------
qiQfhyAvDDPD7muJLtGdZudKqMug0aAC | {"cookie":{"originalMaxAge":2592000000,"expires":"2017-09-30T10:55:31.514Z","secure":false,"httpOnly":true,"path":"/"},"passport":{"user":1}} | 2017-09-30 13:55:32
(1 row)
到目前为止,非常好。
现在,我正在请求网站的主页并获得以下内容:
info: GET / 200 486ms statusCode=200, url=/, host=localhost:3000, accept-encoding=gzip, deflate, cookie=connect.sid=s%3AO6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE.M4iFzpVZP9fNa%2FLEomsMD8D9LjA1uFnDMnXT%2FHR3wyk; meteor_login_token=4YvVuK0V4adQJaMM2setEAx9_Ki7q6At19YfAvwyOJ8; _ga=GA1.1.1413606909.1501852025, connection=keep-alive, upgrade-insecure-requests=1, accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8, user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8, referer=http://localhost:3000/user/login, cache-control=max-age=0, accept-language=ru, method=GET, httpVersion=1.1, originalUrl=/, , responseTime=486, user=null
express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +516ms
express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +1ms
express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +4ms
express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +1ms
express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +1ms
express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +0ms
express-session no session found +1ms
Authentication status:
req.cookies: undefined
req.isAuthenticated: false
req.session: Session {
cookie:
{ path: '/',
_expires: 2017-09-30T11:15:52.123Z,
originalMaxAge: 2592000000,
httpOnly: true,
secure: false } }
Not logged in
express-session no session found +7ms
我知道,'express-session'尝试使用另一个SID O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE
获取会话,这在数据库中不存在。
为什么会这样?
AFAIK,它应该通过SID = qiQfhyAvDDPD7muJLtGdZudKqMug0aAC
...
我的设置可能会出现什么问题?
一个秘密密钥,'cookie-parser'没有被使用,根据重新编写'注意从版本1.5.0开始,cookie解析器中间件不再需要'...
我完全坚持这个。
请帮助。
sid生成出了点问题
当我手动更改存储的会话sid
以使其与express-session
请求的内容匹配时,
UPDATE session SET sid='O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE' WHERE sid='qiQfhyAvDDPD7muJLtGdZudKqMug0aAC';
会话被正确获取并且用户被持久化:
express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +3s
express-session session found +2ms
> deserializeUser with id: 1
Executing (default): SELECT "id", "nickname", "email", "password", "passwordHash", "lastLoggedIn", "createdAt", "updatedAt" FROM "users" AS "user" WHERE "user"."id" = 1;
Authentication status:
req.cookies: undefined
req.isAuthenticated: true
req.session: Session {
cookie:
{ path: '/',
_expires: 2017-09-30T10:55:31.514Z,
originalMaxAge: 2592000000,
httpOnly: true,
secure: false },
passport: { user: 1 } }
Logged in as "AntonAL"
express-session saving O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +577ms
express-session split response +1ms
info: GET / 200 585ms statusCode=200, url=/, host=localhost:3000, accept-encoding=gzip, deflate, cookie=connect.sid=s%3AO6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE.M4iFzpVZP9fNa%2FLEomsMD8D9LjA1uFnDMnXT%2FHR3wyk; meteor_login_token=4YvVuK0V4adQJaMM2setEAx9_Ki7q6At19YfAvwyOJ8; _ga=GA1.1.1413606909.1501852025, connection=keep-alive, upgrade-insecure-requests=1, accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8, user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8, referer=http://localhost:3000/user/login, cache-control=max-age=0, accept-language=ru, method=GET, httpVersion=1.1, originalUrl=/, , responseTime=585, user=AntonAL
所以,现在很明显 - sid参数不同,在生成会话并获取它时。
答案 0 :(得分:0)
想出来。
在客户端代码中,我使用fetch
函数,代码如下:
fetch('/user/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(values)
});
这种方法给我带来了问题。
当我将请求方法更改为' GET'在路由和使用普通重定向,我得到它的一切工作。
window.location.href = "/login?"+querystring.stringify(values);
为什么会这样?