Node.js 护照使用者&;反序列化用户
关于这场争论,我已经读了所有的东西,但仍然不能理解。Passport Js网站上的文档非常模糊 我使用Passport JS和Passport ldapauth策略我没有数据库我显然不想在每次请求时都点击LDAP服务器。我想第一次在POSTNode.js 护照使用者&;反序列化用户,node.js,session,authentication,ldap,passport.js,Node.js,Session,Authentication,Ldap,Passport.js,关于这场争论,我已经读了所有的东西,但仍然不能理解。Passport Js网站上的文档非常模糊 我使用Passport JS和Passport ldapauth策略我没有数据库我显然不想在每次请求时都点击LDAP服务器。我想第一次在POST/login路由上使用LDAP的passport策略对用户进行身份验证,将用户存储在会话中,然后在每次后续请求中,我只想检查用户是否已经登录 我正在尝试使用会话,但我无法理解如何将Passport+会话与序列化/反序列化流一起使用。我检查的每个示例都在反序列化
/login
路由上使用LDAP的passport策略对用户进行身份验证,将用户存储在会话中,然后在每次后续请求中,我只想检查用户是否已经登录
我正在尝试使用会话,但我无法理解如何将Passport+会话与序列化/反序列化流一起使用。我检查的每个示例都在反序列化用户函数中使用User.findOne
到目前为止,我已禁用Passport会话的使用,我正在使用一个自定义中间件,在其中检查req.session.user!=空
。如果是这种情况,用户已经登录,我点击next()
。否则重定向到登录
以下是一些代码(为了简单起见,我删除了与问题无关的代码):
护照配置:
var express = require('express'),
session = require('express-session'),
passport = require('passport'),
LdapStrategy = require('passport-ldapauth');
var app = express();
var LdapStrategyOptions = {
server: {
url: '<url>',
bindDN: '<dn>',
bindCredentials: "<pwd>",
searchBase: '<searchBase>',
searchFilter: '<filter>'
}
};
passport.use(new LdapStrategy(LdapStrategyOptions));
app.use(cookieParser());
app.use(session({
store: new LokiStore({autosave: false}),
resave: false,
saveUninitialized: false
secret: env.get("SESSION_SECRET")
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
// LOGIN ROUTE
app.get('/login',
function(req, res) {
res.render('login');
});
// LOGIN HANDLER ROUTE
app.post('/login',
passport.authenticate('ldapauth', { session: false }),
function(req, res) {
req.session.userId = req.user.cn;
req.session.user = {
"userId": req.user.cn,
"displayName": req.user.displayName
};
res.redirect('/');
});
// LOGOUT ROUTE
app.get('/logout',
function(req, res) {
req.session.destroy(function(err) {
req.logout();
res.redirect('/');
});
});
// HOME ROUTE
app.get('/', isLoggedIn, function(req, res) {
res.render('home');
});
var isLoggedIn = function(req, res, next) {
if (req.session.user != null){
console.log("is auth ok '" + req.session.user.userId +"'");
return next();
}
console.log("redirect to auth/login");
res.redirect('/auth/login');
}
IsLoggedIn中间件:
var express = require('express'),
session = require('express-session'),
passport = require('passport'),
LdapStrategy = require('passport-ldapauth');
var app = express();
var LdapStrategyOptions = {
server: {
url: '<url>',
bindDN: '<dn>',
bindCredentials: "<pwd>",
searchBase: '<searchBase>',
searchFilter: '<filter>'
}
};
passport.use(new LdapStrategy(LdapStrategyOptions));
app.use(cookieParser());
app.use(session({
store: new LokiStore({autosave: false}),
resave: false,
saveUninitialized: false
secret: env.get("SESSION_SECRET")
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
// LOGIN ROUTE
app.get('/login',
function(req, res) {
res.render('login');
});
// LOGIN HANDLER ROUTE
app.post('/login',
passport.authenticate('ldapauth', { session: false }),
function(req, res) {
req.session.userId = req.user.cn;
req.session.user = {
"userId": req.user.cn,
"displayName": req.user.displayName
};
res.redirect('/');
});
// LOGOUT ROUTE
app.get('/logout',
function(req, res) {
req.session.destroy(function(err) {
req.logout();
res.redirect('/');
});
});
// HOME ROUTE
app.get('/', isLoggedIn, function(req, res) {
res.render('home');
});
var isLoggedIn = function(req, res, next) {
if (req.session.user != null){
console.log("is auth ok '" + req.session.user.userId +"'");
return next();
}
console.log("redirect to auth/login");
res.redirect('/auth/login');
}
我错过了什么?我的设置中是否存在任何安全错误?
感谢您的帮助 来自文档:
在典型的web应用程序中,用于验证用户身份的凭据仅在登录请求期间传输。如果身份验证成功,将通过用户浏览器中的cookie集建立和维护会话
每个后续请求将不包含凭据,而是标识会话的唯一cookie。为了支持登录会话,Passport将序列化和反序列化会话中的用户实例
基本上,serializeUser
应该返回一个唯一的用户标识符,以便以后可以反序列化user
返回到JSON中
因此,对于您的实现,您可能应该按照以下思路做一些事情:
免责声明:我没有LDAP方面的经验
passport.serializeUser(function(user, done) {
//We can identify the user uniquely by the CN,
//so we only serialize this into the session token.
done(null, user.cn);
});
passport.deserializeUser(function(cn, done) {
//Directly query LDAP.
//I'm not sure passport caches the result (only calls deserializeUser for new sessions)
//but worst case you can cache the result yourself.
somehowLoadUserFromLDAPByCN(cn, function(err, user) {
done(err, {
userId: user.cn,
displayName: user.displayName
});
});
});
如果您只需要一个id和一个显示名,那么将它们保持在会话中是完全可以的。您应该只在需要更多字段时加载完整的用户配置文件。是否可能缺少
app.use(passport.session())代码>?否。我从示例代码中删除了它,因为在编写时,我没有使用它,因为我无法理解应该在passport.deserializeUser()中编写什么。示例cose正是我发现的使其与自定义会话管理一起工作的方法!但问题是,我不想在每个请求上都使用LDAP(资源密集型流程)。数据库也是如此。为什么每次请求都要查询数据库?这正是我在passport框架中不理解的。我记不起passport是否处理此函数结果的缓存。您可以通过设置断点来检查自己,并查看是否在您已通过身份验证的情况下调用了断点。我的假设是不会(因为passport不知道您是否要缓存这些结果。您可以在这个函数中自己缓存结果,只有在缓存未命中时,才点击LDAP查询)。缓存的实现取决于您(内存、redis等)。即使您已经通过身份验证,也会在每个请求上调用反序列化用户。我仍然不知道这个函数的目的是什么。我究竟为什么要在每次请求时都点击auth系统(DB、LDAP、facebook服务)?如果我可以使用会话存储用户名、电子邮件和其他信息,为什么我要将用户配置文件缓存在数据库中?因为有时您的数据库包含有关该用户的其他信息(例如角色)