Passport.js 多个本地策略和 req.user
Passport.js multiple local strategies and req.user
我的网络应用程序的客户端想要 完全 将普通用户和管理员分开,因此我正在尝试为 passport.js
实施两个本地策略:
passport.use('local', new LocalStrategy({
usernameField: 'email'
}, function(email, password, done) {
User.findOne({ email: email }, function(err, user) {
if (err) return done(err);
if (!user) return done(null, false, { message: 'Wrong email or password.' });
if (!user.validPassword(password)) return done(null, false, { message: 'Wrong email or password.' });
done(null, user);
});
}));
passport.use('admin', new LocalStrategy({
usernameField: 'email'
}, function(email, password, done) {
Admin.findOne({ email: email }, function(err, admin) {
if (err) return done(err);
if (!admin) return done(null, false, { message: 'Wrong email or password.' });
if (!admin.validPassword(password)) return done(null, false, { message: 'Wrong email or password.' });
done(null, admin);
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
Admin.findById(id, function(err, admin) {
if (err) return done(err);
if (admin) return done(null, admin);
User.findById(id, function(err, user) {
done(err, user);
});
});
});
然后在我的 API 管理路由器中:
router.post('/', function(req, res, next) {
if (typeof req.body.email === 'undefined') return res.json({ success: false, message: 'Email not supplied.' });
if (!validator.isEmail(req.body.email)) return res.json({ success: false, message: 'Wrong email format.' });
if (typeof req.body.password === 'undefined') return res.json({ success: false, message: 'Password not supplied.' });
if (req.body.password.length === 0) return res.json({ success: false, message: 'Password not supplied.' });
passport.authenticate('admin', function(err, admin, info) {
if (!admin) return res.json({ success: false, message: info.message });
req.logIn(admin, function(err) {
if (err) return res.json({ success: false, message: 'Server error.', reason: err });
console.log('user:');
console.log(req.user); // both users and admins go here
console.log('admin:');
console.log(req.admin); // undefined
res.json({ success: true });
});
})(req, res, next);
});
事实上,我一直在关注这里的答案:,而 Matthew Payne 得到了两个会话变量:req.user
和 req.sponsor
。在我的例子中,即使管理员进行身份验证,它也会被写入 req.user
。现在,为了实现我的客户完全分离用户和管理员的愿望,我想获得 req.user
和 req.admin
,但每次都写入 req.user
。我认为更改 LocalStrategy 名称会有所帮助,但 passport.js
似乎忽略了策略名称 和 模型名称。
非常感谢任何帮助。
P.S。我知道我可以让每个人都处于 User
模型中并编写一些中间件来根据角色保护某些路由,但不幸的是,我不能在这里选择。
很遗憾,您无法使用 Passport 执行此操作。您将需要创建快速中间件来处理管理员身份验证。
就像 Hya 回答的那样,护照不利于授权...
您需要使用中间件来设置管理上下文和管理角色:
// add this middlewares after your routes...
// set admin context and others things like admin templates
app.use('/admin/*', function adminContext(req, res, next) {
// set admin context
req.isAdmin = true;
next();
});
// then get roles for authenticated user in your passport stategy:
app.use(function getUserRoles(req, res, next) {
req.userRoleNames = [];
if (req.isAuthenticated()) {
req.userRoleNames.push('authenticated');
} else {
req.userRoleNames.push('unAuthenticated');
return next(); // skip role load if dont are authenticated
}
// get user roles, you may get roles from DB ...
// and if are admin add its role
req.userRoleNames.push('administrator');
next();
});
// and check roles in admin page
app.get('/admin/admin-page/', function (req, res, next) {
if (req.userRoleNames.indexOf('administrator') == -1) return res.status(403).send('forbidden');
console.log('roles:', req.userRoleNames);
res.status(200).send('Hey you are the administrator!');
});
请参阅 we.js 核心以查看一种高级角色和权限实现:https://github.com/wejs/we-core
我的网络应用程序的客户端想要 完全 将普通用户和管理员分开,因此我正在尝试为 passport.js
实施两个本地策略:
passport.use('local', new LocalStrategy({
usernameField: 'email'
}, function(email, password, done) {
User.findOne({ email: email }, function(err, user) {
if (err) return done(err);
if (!user) return done(null, false, { message: 'Wrong email or password.' });
if (!user.validPassword(password)) return done(null, false, { message: 'Wrong email or password.' });
done(null, user);
});
}));
passport.use('admin', new LocalStrategy({
usernameField: 'email'
}, function(email, password, done) {
Admin.findOne({ email: email }, function(err, admin) {
if (err) return done(err);
if (!admin) return done(null, false, { message: 'Wrong email or password.' });
if (!admin.validPassword(password)) return done(null, false, { message: 'Wrong email or password.' });
done(null, admin);
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
Admin.findById(id, function(err, admin) {
if (err) return done(err);
if (admin) return done(null, admin);
User.findById(id, function(err, user) {
done(err, user);
});
});
});
然后在我的 API 管理路由器中:
router.post('/', function(req, res, next) {
if (typeof req.body.email === 'undefined') return res.json({ success: false, message: 'Email not supplied.' });
if (!validator.isEmail(req.body.email)) return res.json({ success: false, message: 'Wrong email format.' });
if (typeof req.body.password === 'undefined') return res.json({ success: false, message: 'Password not supplied.' });
if (req.body.password.length === 0) return res.json({ success: false, message: 'Password not supplied.' });
passport.authenticate('admin', function(err, admin, info) {
if (!admin) return res.json({ success: false, message: info.message });
req.logIn(admin, function(err) {
if (err) return res.json({ success: false, message: 'Server error.', reason: err });
console.log('user:');
console.log(req.user); // both users and admins go here
console.log('admin:');
console.log(req.admin); // undefined
res.json({ success: true });
});
})(req, res, next);
});
事实上,我一直在关注这里的答案:,而 Matthew Payne 得到了两个会话变量:req.user
和 req.sponsor
。在我的例子中,即使管理员进行身份验证,它也会被写入 req.user
。现在,为了实现我的客户完全分离用户和管理员的愿望,我想获得 req.user
和 req.admin
,但每次都写入 req.user
。我认为更改 LocalStrategy 名称会有所帮助,但 passport.js
似乎忽略了策略名称 和 模型名称。
非常感谢任何帮助。
P.S。我知道我可以让每个人都处于 User
模型中并编写一些中间件来根据角色保护某些路由,但不幸的是,我不能在这里选择。
很遗憾,您无法使用 Passport 执行此操作。您将需要创建快速中间件来处理管理员身份验证。
就像 Hya 回答的那样,护照不利于授权...
您需要使用中间件来设置管理上下文和管理角色:
// add this middlewares after your routes...
// set admin context and others things like admin templates
app.use('/admin/*', function adminContext(req, res, next) {
// set admin context
req.isAdmin = true;
next();
});
// then get roles for authenticated user in your passport stategy:
app.use(function getUserRoles(req, res, next) {
req.userRoleNames = [];
if (req.isAuthenticated()) {
req.userRoleNames.push('authenticated');
} else {
req.userRoleNames.push('unAuthenticated');
return next(); // skip role load if dont are authenticated
}
// get user roles, you may get roles from DB ...
// and if are admin add its role
req.userRoleNames.push('administrator');
next();
});
// and check roles in admin page
app.get('/admin/admin-page/', function (req, res, next) {
if (req.userRoleNames.indexOf('administrator') == -1) return res.status(403).send('forbidden');
console.log('roles:', req.userRoleNames);
res.status(200).send('Hey you are the administrator!');
});
请参阅 we.js 核心以查看一种高级角色和权限实现:https://github.com/wejs/we-core