我正在开发一个使用 MEAN 技术栈的应用,项目中使用了 Angular 4。在认证方面,我使用了 Passport.js 的Local-strategy
,并使用了Express-session
来保持持久会话。到目前为止,一切都很顺利。
问题
在同一域中,session
可以正常工作,并且我能够对用户进行身份验证。但是在跨域中,我无法保持会话,每个新请求都会生成一个新的会话 ID。
然后我尝试了Passport-jwt
,但它的问题是我无法控制用户会话。我的意思是,如果用户处于非活动状态,我不能从服务器注销用户,甚至在服务器重新启动时token
也不会失效。
因此简而言之,我正在寻找一个Node.js(Express.js)身份验证解决方案,可以管理跨域身份验证。
我已经阅读了一些博客文章和类似于这样的 SO 问题,但它们都没有帮助。
谢谢。
编辑
我应该编写自己的代码来实现此功能吗?如果是这样,我有一个计划。
我的基本计划是:
- 用户将在登录请求中发送凭据。
- 我将在数据库中检查凭据。如果凭据有效,我将生成一个随机令牌并将其保存到用户表中,并将同一令牌提供给用户以获得成功响应。
- 现在,每个请求用户都会发送令牌,我将在数据库中检查每个请求的令牌。如果令牌有效,则允许用户访问 API,否则将生成具有401状态代码的错误。
- 我使用 Mongoose (MongoDB),所以从性能角度考虑,每个请求中检查令牌都是可以接受的。
我认为这也是一个好主意。我只想要一些建议,无论我是否朝着正确的方向思考。
我将得到以下内容:
- 应用程序中已登录用户的数量(活动会话)。
- 如果用户处于空闲状态,我可以注销用户。
- 我可以管理同一用户的多个登录会话(通过在数据库中进行记录)。
- 我可以允许最终用户清除所有其他登录会话(就像 Facebook 和 Gmail 一样)。
- 与授权相关的任何自定义。
编辑 2
我在这里分享我的app.js
代码。
var express = require('express');
var helmet = require('helmet');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var dotenv = require('dotenv');
var env = dotenv.load();
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var session = require('express-session');
var cors = require('cors');
var databaseUrl = require('./config/database.js')[process.env.NODE_ENV || 'development'];
// configuration
mongoose.connect(databaseUrl); // connect to our database
var app = express();
// app.use(helmet());
// required for passport
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if ('OPTIONS' == req.method) {
res.send(200);
} else {
next();
}
});
app.use(cookieParser());
app.use(session({
secret: 'ilovescotchscotchyscotchscotch', // session secret
resave: true,
saveUninitialized: true,
name: 'Session-Id',
cookie: {
secure: false,
httpOnly: false
}
}));
require('./config/passport')(passport); // pass passport for configuration
var index = require('./routes/index');
var users = require('./routes/user.route');
var seeders = require('./routes/seeder.route');
var branches = require('./routes/branch.route');
var companies = require('./routes/company.route');
var dashboard = require('./routes/dashboard.route');
var navigation = require('./routes/navigation.route');
var roles = require('./routes/role.route');
var services = require('./routes/services.route');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
require('./routes/auth.route')(app, passport);
app.use('/', index);
app.use('/users', users);
app.use('/seed', seeders);
app.use('/branches', branches);
app.use('/companies', companies);
app.use('/dashboard', dashboard);
app.use('/navigation', navigation);
app.use('/roles', roles);
app.use('/services', services);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
res.status(404).send({ status: 'NOT_FOUND', message: 'This resource is not available.'});
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
let errorObj = {
status: 'INTERNAL_SERVER_ERROR',
message: 'Something went wrong.',
error: err.message
};
res.status(err.status || 500).send(errorObj);
});
module.exports = app;
编辑3
对于那些不理解我的问题的人,我用简单的话来解释一下:
- 我的Express服务器运行在3000端口。
- 为了使用来自服务器的API,用户必须先登录。
- 当一个用户从
localhost:3000
登录时,服务器使用Passport-local检查凭据并在响应头中返回一个令牌。 - 现在,在登录后,当一个用户访问
localhost:3000
的任何API时,一个预定义的Header
会随着passport-session
一起被发送,然后passport会使用req.isAuthenticated()
验证用户会话,并且所有东西都按预期工作。 - 当一个用户从
localhost:4000
登录并且服务器在响应头中发送一个令牌(与localhost:3000
相同)时。 - 当成功登录后,用户从
localhost:4000
访问任何API时,passport js函数req.isAuthenticated()
会返回false
。 - 这是因为在跨域时,
cookie
不会传递到服务器,我们需要在客户端设置withCredentials
头为true
。 - 我已将
withCredentials
头设置为true
,但仍然在服务器上,req.isAuthenticated()
返回false
。
Express-session
上,如果我们处于跨域状态下,服务器会在每个请求上生成新的会话。 - Arpit Kumarlocalhost:3000
和localhost:4000
是不同的域。它们不是,域名是localhost
,它们是相同的。我猜您设置了错误的Passport。 - kkkkkkk