使用 Passportjs 刷新页面后保持身份验证

Posted

技术标签:

【中文标题】使用 Passportjs 刷新页面后保持身份验证【英文标题】:Staying authenticated after the page is refreshed using Passportjs 【发布时间】:2015-06-25 14:30:55 【问题描述】:

我正在使用 expressmongoosepassportjs 构建 SPA。

我为我的用户创建了一个简单的架构:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');

var User = new Schema(
    username: String,
    password: String,
    first_name: String
,  collection: 'users' );

User.plugin(passportLocalMongoose);

mongoose.model('User', User);

使用 mongoose 给我的 User 对象配置护照:

passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());         
passport.deserializeUser(User.deserializeUser());

并配置我的应用程序在导航到此路线时对用户进行身份验证:

app.post('/login', passport.authenticate('local'), function(req, res, next) 
    if (req.isAuthenticated()) 
        return res.json( state: 'success', user:  first_name: req.user.first_name  );    
    
    return res.json( state: 'failure', message: 'cannot authenticate' );
);

现在我可以成功验证用户身份。并且浏览器会保存一个会话 id cookie。

我的问题是每次用户刷新页面护照都不会使用会话ID反序列化用户,是什么使用户未经身份验证。

访问站点根目录中的req.user 对象时,我得到undefined,这让我意识到护照没有正确反序列化用户:

app.use('/', function (req, res, next) 
    console.log(req.user); // prints undefined.        

    next();
);

刷新页面后恢复用户的正确方法是什么?

【问题讨论】:

Mongoose 必须反序列化用户,如果您调用的是 passport.deserializeUser(User.deserializeUser()); 【参考方案1】:

解决方案是将会话存储在 DB 中。我用connect-mongo。

app.js:

var mongoose = require('mongoose');
var expressSession = require('express-session');
var MongoStore = require('connect-mongo')(expressSession);

mongoose.connect(db_url, function (err) 
    if (err) 
        console.log(err);
    
);

app.use(expressSession(
    secret: process.env.SESSION_SECRET || 'keyboard cat',
    resave: false,
    saveUninitialized: false,
    store: new MongoStore( mongooseConnection: mongoose.connection )
));

此后,req.isAuthenticated() 在每次请求时都会返回 true,即使在刷新页面后也是如此。 (感谢app.use(passport.session()),它出现在任何路由处理程序之前)

app.use('/', function (req, res, next) 
    if (req.isAuthenticated()) 
        // returns true if a user already logged in.
    
    next();
);

【讨论】:

var session = require('express-session'); var MongoStore = require('connect-mongo/es5')(express); app.use(express.session( secret: process.env.SESSION_SECRET || '这是秘密', resave: false, saveUninitialized: false, store: new MongoStore( mongooseConnection: mongoose.connection ) ));刷新时它仍然登录??【参考方案2】:

看你的帖子我可以猜出问题出在哪里。有问题的是,您已经粘贴了后端 expressjs 代码,但问题发生在前端。

想想当你在处理普通的 javascript 文件时,你使用 firebug n all 的 Chrome 开发工具对变量值进行了一些编辑。假设您刷新页面,您仍然在视图中看到相同的编辑值吗?没有权利。您的观点也是如此,您暂时持有用户数据。尽管您的后端保存了 req.user 中的值,但您的前端在刷新时会丢失它。

所以你必须做以下两个:

在成功登录时将您的值存储在 cookie 中,并在成功登录时将其删除 登出。这样 cookie 就永远不会丢失数据,即使您 刷新页面。随时访问该 cookie 中的用户数据 调用后端 API,返回 req.user 的值 页面刷新

我不确定您为 SPA 使用的是什么前端框架,如果您使用的是 AngularJS,那么您可以使用 cookieStore 服务,它可以很好地完成这项工作。

【讨论】:

问题是即使在刷新页面后,我也可以通过使用 Chrome 开发工具在浏览器中看到 sessionid cookie。是的,我正在使用 AngularJS 我试图向您解释可能的情况。刷新后前端的值被刷新,你需要调用req.user来取回它。 好的,所以这可能不是这种情况,因为我可以看到刷新页面后该值仍然存在,当我尝试访问 req.user 时,我得到 undefined

以上是关于使用 Passportjs 刷新页面后保持身份验证的主要内容,如果未能解决你的问题,请参考以下文章

身份验证后使用 passportjs-google 重定向到原始页面(无会话)

服务器端 Blazor:刷新页面后如何保持用户身份验证?

无法保持页面刷新会话

页面刷新后如何保持用户登录

如何使用 Firebase 刷新令牌保持用户身份验证?

如何设置PassportJS进行后端身份验证?