node.js 护照登录和持久化会话
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36486397/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passport login and persisting session
提问by Joe Lloyd
Background
背景
I have a MEAN application with CRUD capabilities fully tested with postman. I have been trying to persist login for quite some time now with no luck. I have read and tried the following
我有一个带有 CRUD 功能的 MEAN 应用程序,它经过邮递员的全面测试。我一直在尝试坚持登录很长一段时间,但没有运气。我已经阅读并尝试了以下内容
- passport docs
- toon io's blog about login
- Express session
- Scotch io, node auth made easy
- Plus a buch of other light reading materials (Lots of SO questions)
- 护照文件
- toon io 关于登录的博客
- 快速会话
- Scotch io,节点身份验证变得简单
- 加上一些其他的轻读材料(很多 SO 问题)
But I have only been able to register and log a user in, not persist login with a session.
但是我只能注册和登录用户,不能通过会话持续登录。
My App
我的应用程序
Hereis a link to the full github repo (if you are looking for the latest changes check develop branch)
这是完整 github 存储库的链接(如果您正在寻找最新的更改,请查看开发分支)
My Understanding of Auth/Login
我对认证/登录的理解
Here is my understanding of user login with code examples from my project and screenshot of postman results as well as console logs.
这是我对用户登录的理解,包括我的项目中的代码示例、邮递员结果的屏幕截图以及控制台日志。
Passport setup
护照设置
I have the following auth.js file, it configs passport
我有以下 auth.js 文件,它配置了护照
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
module.exports = function(app, user){
app.use(passport.initialize());
app.use(passport.session());
// passport config
passport.use(new LocalStrategy(user.authenticate()));
passport.serializeUser(function(user, done) {
console.log('serializing user: ');
console.log(user);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
user.findById(id, function(err, user) {
console.log('no im not serial');
done(err, user);
});
});
};
This gets called in the server file like
这在服务器文件中被调用,如
//code before
var user = require('./models/user.js');
var auth = require('./modules/auth.js')(app, user);
// code after
Routing for login
登录路由
In my routes I have the login route as follows
在我的路线中,我的登录路线如下
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
res.status(200).json({
status: 'Login successful!'
});
});
})(req, res, next);
});
This route worksas tested with postman. I enter the details 'joe' and 'pass' and get the following response.
这条路线的工作原理与邮差测试。我输入详细信息“joe”和“pass”并得到以下响应。
When this route is hit we can also see in the console that the user is serialized.
当这条路由被命中时,我们也可以在控制台中看到用户被序列化了。
So what next?
那么接下来呢?
This is where I get lost. I have a few questions.
这是我迷路的地方。我有几个问题。
- Is the user now in a session on my server?
- Should I send the
req.session.passport.userback to the client? - Do I need the session ID on all future requests?
- 用户现在是否在我的服务器上进行会话?
- 我应该把
req.session.passport.user回寄给客户吗? - 我是否需要在以后的所有请求中使用会话 ID?
Testing the Session
测试会话
I have a second route setup for testing the session it is as follows
我有用于测试会话的第二个路由设置,如下所示
router.get('/checkauth', passport.authenticate('local'), function(req, res){
res.status(200).json({
status: 'Login successful!'
});
});
The part passport.authenticate('local')(I thought) is there to test if the user session exists before giving access to the route but I never get a 200 response when I run this, even after a login.
这部分passport.authenticate('local')(我认为)是在允许访问路由之前测试用户会话是否存在,但是当我运行它时,即使登录后我也从未收到 200 响应。
Does this route expect a req.session.passport.userpassed in the head or as a data argument on a http request that requires auth?
此路由是否req.session.passport.user需要在需要身份验证的 http 请求中传入头部或作为数据参数?
If I missed anything or am understanding something wrong please tell me, any input is appreciated. Thanks all.
如果我遗漏了任何内容或理解错误,请告诉我,感谢您提供任何意见。谢谢大家。
回答by hassansin
Is the user now in a session on my server?
用户现在是否在我的服务器上进行会话?
No, You need to use the express-sessionmiddleware before app.use(passport.session());to actually store the session in memory/database. This middleware is responsible for setting cookies to browsers and converts the cookies sent by browsers into req.sessionobject. PassportJS only uses that object to further deserialize the user.
不,您需要先使用express-session中间件才能app.use(passport.session());将会话实际存储在内存/数据库中。该中间件负责为浏览器设置cookies,并将浏览器发送的cookies转化为req.session对象。PassportJS 仅使用该对象来进一步反序列化用户。
Should I send the req.session.passport.user back to the client?
我应该将 req.session.passport.user 发送回客户端吗?
If your client expects a userresource upon login, then you should. Otherwise, I don't see any reason to send the user object to the client.
如果您的客户user在登录时需要资源,那么您应该这样做。否则,我看不出有任何理由将用户对象发送给客户端。
Do I need the session ID on all future requests?
我是否需要在以后的所有请求中使用会话 ID?
Yes, for all future requests, the session id is required. But if your client is a browser, you don't need to send anything. Browser will store the session id as cookie and will send it for all subsequent requests until the cookie expires. express-sessionwill read that cookie and attach the corresponding session object as req.session.
是的,对于所有未来的请求,会话 ID 是必需的。但是如果你的客户端是浏览器,你就不需要发送任何东西。浏览器将会话 id 存储为 cookie,并将为所有后续请求发送它,直到 cookie 过期。express-session将读取该 cookie 并将相应的会话对象附加为req.session.
Testing the Session
测试会话
passport.authenticate('local')is for authenticating user credentials from POST body. You should use this only for login route.
passport.authenticate('local')用于从 POST 正文验证用户凭据。您应该仅将其用于登录路由。
But to check if the user is authenticated in all other routes, you can check if req.useris defined.
但是要检查用户是否在所有其他路由中经过身份验证,您可以检查是否req.user已定义。
function isAuthenticated = function(req,res,next){
if(req.user)
return next();
else
return res.status(401).json({
error: 'User not authenticated'
})
}
router.get('/checkauth', isAuthenticated, function(req, res){
res.status(200).json({
status: 'Login successful!'
});
});
回答by yeiniel
As @hassansin says you need to use a middleware that implement session management. The passport.session() middleware is to connect the passport framework to the session management and do not implement session by itself. You can use the express-sessionmiddlewareto implement session management. You need to modify your auth.js in the following way
正如@hassansin 所说,您需要使用实现会话管理的中间件。passport.session() 中间件是将passport 框架连接到会话管理,本身并不实现会话。您可以使用express-session中间件来实现会话管理。您需要通过以下方式修改您的 auth.js
var passport = require('passport');
var session = require('express-session');
var LocalStrategy = require('passport-local').Strategy;
module.exports = function(app, user){
app.use(session({secret: 'some secret value, changeme'}));
app.use(passport.initialize());
app.use(passport.session());
// passport config
passport.use(new LocalStrategy(user.authenticate()));
passport.serializeUser(function(user, done) {
console.log('serializing user: ');
console.log(user);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
user.findById(id, function(err, user) {
console.log('no im not serial');
done(err, user);
});
});
};
Notice that in this case the session engine is using the in memory store and it didn't work if you scale your application and apply load balancing. When you reach this development state something like the connect-redissession storewill be needed.
请注意,在这种情况下,会话引擎使用内存存储,如果您扩展应用程序并应用负载平衡,它就不起作用。当您达到此开发状态时,将需要诸如connect-redis会话存储之类的东西。
Also notice that you need to change the secret value used on the session midleware call and use the same value on all application instances.
另请注意,您需要更改会话中间件调用中使用的秘密值,并在所有应用程序实例上使用相同的值。
回答by Michael Hamilton
As per the passport documentation, req.userwill be set to the authenticated user. In order for this to work though, you will need the express-sessionmodule. You shouldn't need anything else beyond what you already have for passport to work.
根据护照文档,req.user将设置为经过身份验证的用户。但是,为了使其工作,您将需要该express-session模块。除了您已有的护照工作之外,您不应该需要任何其他东西。
As far as testing the session, you can have a middleware function that checks if req.user is set, if it is, we know the user is authenticated, and if it isn't, you can redirect the user.
至于测试会话,你可以有一个中间件函数来检查 req.user 是否设置,如果是,我们知道用户已经过身份验证,如果不是,你可以重定向用户。
You could for example have a middleware function that you can use on any routes you want authenticated.
例如,您可以拥有一个中间件功能,您可以在任何要进行身份验证的路由上使用该功能。
authenticated.js
认证.js
module.exports = function (req, res, next) {
// if user is authenticated in the session, carry on
if (req.user) {
next();
}
// if they aren't redirect them to the login page
else {
res.redirect('/login');
}
};
controller
控制器
var authenticated = require('./authenticated');
router.get('/protectedpage', authenticated, function(req, res, next) {
//Do something here
});
回答by tcmoore
I don't know of a way to check all existing sessions, but Passport is handling the issuing of session ids. Try checking that you have req.user on your test endpoint after logging in
我不知道有什么方法可以检查所有现有会话,但 Passport 正在处理会话 ID 的发布。登录后尝试检查您的测试端点上是否有 req.user
回答by Hyman
Passport.js does not work well as it stores the session in the server (bad and not scalable). You don't want to store any session data in the server (keeping it stateless) as then you may scale up your clusters and handle more requests.
Passport.js 不能很好地工作,因为它将会话存储在服务器中(糟糕且不可扩展)。您不想在服务器中存储任何会话数据(保持无状态),因为这样您可能会扩展集群并处理更多请求。
If you look at the code in the Passport.js library, there isn't much.. Building it yourself can actually be faster and more efficient.
如果您查看 Passport.js 库中的代码,就会发现并没有太多……您自己构建它实际上可以更快更高效。
Here is a tutorial I wrote on connecting to Google in a much better way.


