我有一个API,可以使用浏览器调用,其中请求是事务性的,并且直接具有会话OR,例如。使用curl,其中请求是原子的。浏览器请求必须首先进行身份验证,然后使用快速会话(connect.sid)进行后续授权,直接API调用使用标头:Authorization: "SOMETOKEN"
必须为每个请求发送。
我遇到的问题是,因为我使用相同的Web服务器来提供原子和事务流量,所以每次API调用都会被Express发送给会话。每个响应都包含一个Set-Cookie,所有这些会话都填满了我的会话存储。因此:当请求包含授权标头时,如何阻止Express在内存存储区(Redis)中输入新的sess密钥?
请注意。我得到一个更经典的方法是拥有一个单独的API服务器和一个单独的WEB服务器,但为什么不在一台机器上运行?对我来说,不同之处在于API提供数据,WEB提供视图,但除此之外,它们都是同一个应用程序的一部分。我恰好也允许用户直接访问他们的数据,不要强迫他们使用我的界面。
module.exports = function(app, exp, sessionStore, cookieParser, passport, flash) {
app.configure(function(){
// Templates
app.set('views', ERNEST.root + '/server/views');
app.set('view engine', 'jade');
app.set('view options', { doctype : 'html', pretty : true });
// Allow large files to be uploaded (default limit is 100mb)
app.use(exp.limit('1000mb'));
// Faux putting and deleting
app.use(exp.methodOverride());
// Static content
app.use(exp.static(ERNEST.root + '/server'));
app.use(exp.static(ERNEST.root + '/public'));
// Handle favicon
app.use(exp.favicon());
// For uploads
app.use(exp.bodyParser({keepExtensions: true}));
// Configure cookie parsing
if ( cookieParser ) app.use(cookieParser);
else app.use(exp.cookieParser());
// Where to store the session
var session_options = { 'secret': "and she put them on the mantlepiece" };
if ( sessionStore ) session_options.store = sessionStore;
app.use(exp.session( session_options ));
// Rememberance
app.use( function (req, res, next) {
if ( req.method == 'POST' && req.url == '/authenticate' ) {
if ( req.body.rememberme === 'on' ) {
req.session.cookie.maxAge = 2592000000; // 30*24*60*60*1000 Rememeber 'me' for 30 days
} else {
req.session.cookie.expires = false;
}
}
next();
});
// PassportJS
if ( passport ){
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
}
});
};
app.get('/status/past_week', MID.ensureAuthenticated, MID.markStart, function(req, res) {
WEB.getStatus('week', function(err, statuses){
if ( err ) res.send(500, err);
else res.send(200, statuses);
});
});
MID.ensureAuthenticated = function(req, res, next) {
if ( req.isAuthenticated() ) return next();
else {
isAuthorised(req, function(err, authorised){
if ( err ) return res.redirect('/');
else if ( authorised ) return next();
else return res.redirect('/');
});
}
function isAuthorised(req, callback){
var authHeader = req.headers.authorization;
if ( authHeader ) {
// Has header, verify it
var unencoded = new Buffer(authHeader, 'base64').toString();
var formatted = unencoded.toString().trim();
ACCOUNT.verifyAuth(formatted, callback); // verifyAuth callbacks next() when successful
} else callback(null, false); // No Authorised header
}
};
答案 0 :(得分:18)
试试这个:
var sessionMiddleware = exp.session( session_options );
app.use(function(req, res, next) {
if (req.headers.authorization) {
return next();
}
return sessionMiddleware(req, res, next);
});
答案 1 :(得分:1)
看起来你需要编写自己的会话中间件。 Here's an example。如果你可以创建一个单独的子域名,例如www.example.com用于浏览器会话,而app.example.com用于直接访问它,那么你应该能够几乎完全使用链接的方法,并且不要启动会话对于app.example.com请求。这可能是最直接的方法,通过该方法,呼叫表明它打算通过它进行身份验证的方法,并且任何转移都是错误。
否则,您必须在中间件中检测身份验证令牌,并在找到时不启动会话。
答案 2 :(得分:1)
减少存储在会话存储中的会话数量的另一种方法是将默认maxAge设置为低。然后,当您确实需要存储更长时间的会话时,例如在用户登录后,您可以设置req.session.cookie.expires = null;
。另外,当用户退出时,不要忘记将会话过期设置为低。
以下是一个例子:
// set default to something low
app.use(session({
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 5 * 60 * 1000 // 5 minutes
},
secret: secrets.sessionSecret,
store: new MongoStore({
url: yourUrl,
auto_reconnect: true
})
}));
// on successful login,
// set expiration to null or something longer than default
var time = 14 * 24 * 3600000; //2 weeks
req.session.cookie.maxAge = time;
req.session.cookie.expires = new Date(Date.now() + time);
req.session.touch();
// on logout, reset expiration to something low
var time = 5 * 60 * 1000; // 5 minutes
req.session.cookie.maxAge = time; //2 weeks
req.session.cookie.expires = new Date(Date.now() + time);
req.session.touch();
这在远程监控您的应用时特别有用,因为如果监控频率很高,会话将快速填满。
答案 3 :(得分:-1)
您始终可以捕获响应标头事件并删除'set-cookie'
标头:
app.use(function(req, res, next) {
res.on('header', function () {
if (req.headers.authorization) {
delete res._headers['set-cookie'];
}
});
next();
});
从技术上讲,您可以将它放在中间件链中的任何位置。