angularjs – 更新自定义req.session属性值似乎不够持久
我有一些Express中间件处理来自我的客户端应用程序的GET请求,以便后续请求使用OAuth2令牌的单独API服务器,我也使用快速会话来存储这些令牌.
在我发出传出请求的中间件中,我添加了处理以应对访问令牌到期的情况(API服务器发回403)并发出刷新令牌的请求,之后它将发出相同的原始传出请求API服务器,所以客户端不知道这一切都在发生.然后,通过快速会话将检索到的新令牌持久保存回会话存储,以便在后续请求中使用.令牌也用于设置授权承载令牌标头,您将在下面进一步了解. 以下是我的Express代码中涉及的部分: routes.controller.js //Currently handling GET API requests from client module.exports.fetch = function(req,res) { var options = helpers.buildAPIRequestOptions(req); helpers.performOutgoingRequest(req,res,options); }; helpers.js module.exports.buildAPIRequestOptions = function(req,url) { var options = {}; options.method = req.method; options.uri = 'http://someurl.com' + req.path; options.qs = req.query; options.headers = { 'Authorization': 'Bearer ' + req.session.accessToken }; return options; }; module.exports.performOutgoingRequest = function(req,options) { request(options,function(err,response,body){ if(response.statusCode === 401){ console.log(chalk.red('n--- 401 RESPONSE RECEIVED TRY REFRESHING TOKENS ---')); //Note the third param to call below is a callback and is invoked when calling next() in the refreshToken middleware authController.refreshToken(req,function(){ console.log(chalk.green('n--- RETRYING ORIGINAL REQUEST WITH UPDATED ACCESS TOKEN ---')); //Re-use original request options,but making sure we update the Authorization header beforehand options.headers.Authorization = 'Bearer ' + req.session.accessToken; retryOutgoingRequest(res,options); }); } else { res.status(response.statusCode).send(body); } }); }; function retryOutgoingRequest(res,body){ if(err) { console.log(err); } res.status(response.statusCode).send(body); }); }; auth.controller.js module.exports.refreshToken = function(req,next) { var formData = { grant_type: 'refresh_token',refresh_token: req.session.refreshToken },headers = { 'Authorization' : 'Basic ' + consts.CLIENT_KEY_SECRET_BASE64 }; request.post({url:consts.ACCESS_TOKEN_REQUEST_URL,form:formData,headers: headers,rejectUnauthorized: false},body){ var responseBody = JSON.parse(body); if (response.statusCode === 200) { req.session.accessToken = responseBody.access_token; req.session.refreshToken = responseBody.refresh_token; next(); } else { console.log(chalk.yellow('A problem occurred refreshing tokens,sending 401 HTTP response back to client...')); res.status(401).send(); } }); }; 在大多数情况下,上述工作正常 当用户首次登录时,在将API服务器带到应用程序的主页面之前,会从API服务器获取一些其他用户配置文件信息. 应用程序中的某些页面也会在页面加载时获取数据,因此需要进行访问令牌检查. 在正常使用期间,所以当用户登录并开始在页面周围点击时,我可以看到令牌被换出并在会话存储中通过快速会话保存到期时.根据我编写的中间件,新的访问令牌正确地用于后续请求. 我现在有一个我的中间件不起作用的场景. 所以说我在一个页面加载页面加载数据,让我们说它是一个订单页面.如果我等到API服务器上配置的令牌到期时间已经过去然后刷新浏览器,则客户端应用程序将首先请求用户信息,然后成功将请求页面所需的订单数据(使用AngularJS承诺) 在我的Express应用程序中,用户信息请求从API服务器获取403,因此令牌通过上面的中间件刷新,并且req.session.accessToken得到更新,我可以通过我的服务器应用程序中的控制台日志记录看到.但是,下次获取订单的数据最终会使用先前设置的访问令牌,这会导致API服务器发生进一步的未经授权的错误,因为正在使用无效令牌进行请求. 如果我再次刷新浏览器,则使用先前中间件流中的正确更新令牌获取用户信息和订单. 所以我不确定这里发生了什么,我想知道这是否是一个时间问题,req.session对象没有被及时保留回会话存储区以便下一次请求获取? 任何人都有任何想法可能会发生在这里? 谢谢 更新1 根据评论中的要求,这里是两个请求的请求和响应标头. 第一个请求(使用更新的令牌服务器端) 请求标题 GET /api/userinfo HTTP/1.1 Host: localhost:5000 Connection: keep-alive Accept: application/json,text/plain,*/* User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/50.0.2661.94 Safari/537.36 Referer: https://localhost:5000/ Accept-Encoding: gzip,deflate,sdch Accept-Language: en-GB,en-US;q=0.8,en;q=0.6 Cookie: interact.sid=s%3A0NDG_bn67NeGQAYl1wP1-TmM19ExavFm.Zjv65e9BtSyNBuo%2FDxZEk2Np0963frVur4zHyYw3y5I 响应标题 HTTP/1.1 200 OK X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN Strict-Transport-Security: max-age=86400 X-Download-Options: noopen X-XSS-Protection: 1; mode=block Content-Type: text/html; charset=utf-8 Content-Length: 364 ETag: W/"16c-4AIbpZmTm3I+Yl+SbZdirw" set-cookie: interact.sid=s%3A0NDG_bn67NeGQAYl1wP1-TmM19ExavFm.Zjv65e9BtSyNBuo%2FDxZEk2Np0963frVur4zHyYw3y5I; Path=/; Expires=Fri,13 May 2016 11:54:56 GMT; HttpOnly; Secure Date: Fri,13 May 2016 11:24:56 GMT Connection: keep-alive 第二个请求(使用旧令牌服务器端) 请求标题 GET /api/customers HTTP/1.1 Host: localhost:5000 Connection: keep-alive Accept: application/json,en;q=0.6 Cookie: interact.sid=s%3A0NDG_bn67NeGQAYl1wP1-TmM19ExavFm.Zjv65e9BtSyNBuo%2FDxZEk2Np0963frVur4zHyYw3y5I 响应标题 HTTP/1.1 401 Unauthorized X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN Strict-Transport-Security: max-age=86400 X-Download-Options: noopen X-XSS-Protection: 1; mode=block set-cookie: interact.sid=s%3A0NDG_bn67NeGQAYl1wP1-TmM19ExavFm.Zjv65e9BtSyNBuo%2FDxZEk2Np0963frVur4zHyYw3y5I; Path=/; Expires=Fri,13 May 2016 11:24:56 GMT Connection: keep-alive Content-Length: 0 更新2 我还应该提到我使用connect-mongo作为我的会话存储,我尝试使用默认的内存存储但存在相同的行为.
它听起来像一个竞争条件客户端,如果你正在执行2个请求(检查auth – 然后获取数据)是第二个(获取数据)嵌套到第一次调用成功?或者你是否同时线性地呼叫?
我的想法是: 客户端 – 发送用户信息请求(sessionid 1) – 服务器处理 客户端 – 获取订单信息请求(sessionid 1) – 服务器处理 服务器 – 响应用户信息 – 403 – 客户端更新会话ID 服务器 – 响应订单信息 – 403 你真正想要的是: 客户端 – 发送用户信息请求(会话1) – 服务器处理 server – 获取用户信息请求(403) – 客户端更新会话ID 客户端 – 获取订单信息请求(会话2) – 服务器处理 服务器 – 响应订单信息 – 实际结果 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |