У меня есть обработка промежуточного программного обеспечения Express с моего приложения на стороне клиента для последующего запроса отдельного сервера API, использующего токены OAuth2, я также использую express-session
для хранения этих жетонов.Обновление свойства пользовательского значения req.session, похоже, недостаточно быстро
В моем промежуточном программном обеспечении, которое делает исходящий запрос, я добавил обработку, чтобы справляться с случаями, когда истекает срок доступа к токену доступа (сервер API отправляет обратно 403) и делает запрос на обновление токенов, после чего он выдаст тот же исходный исходящий запрос на сервер API, поэтому клиент не знает об этом. Новые извлеченные токены затем сохраняются обратно в хранилище сеансов через express-session
для использования в последующих запросах. Токены также используются для установки заголовка токена носителя-носителя, как вы увидите ниже.
Вот части моего кода экспресс, который заключается в:
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, res, 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, res, 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, options) {
request(options, function(err, response, body){
if(err) {
console.log(err);
}
res.status(response.statusCode).send(body);
});
};
auth.controller.js
module.exports.refreshToken = function(req, res, 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}, function(err, response, 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();
}
});
};
Для большей части выше работает просто отлично
Когда в первый пользователь LOG, некоторые дополнительная информация Профиль пользователя скачиваются с сервера API, прежде чем они будут приняты к главной странице приложения.
Некоторые страницы в приложении также извлекают данные на загрузку страницы и поэтому подвергаются проверкам токена доступа.
Во время обычного использования, когда пользователь входит в систему и начинает щелкать по страницам, я вижу, что токены выгружаются и сохраняются в хранилище сеансов через express-session
по мере их истечения. Новый токен доступа правильно используется для последующих запросов в соответствии с написанным мной промежуточным программным обеспечением.
У меня теперь есть сценарий, когда мое промежуточное ПО не работает.
Так что скажите, что я на странице, которая загружает данные на загрузку страницы, позволяет сказать ее страницу заказов. Если я подожду до тех пор, пока не истечет время истечения установленного времени токена на сервере API, а затем обновит браузер, клиентское приложение сначала сделает запрос на информацию пользователя, а при успешном запросе запросит данные заказов, необходимые для страницы (используя AngularJS обещает)
В моем экспресс-приложении пользовательский запрос информации получает 403 сервера API, и поэтому токены обновляются с помощью моего промежуточного программного обеспечения выше, и обновляется req.session.accessToken
, которое я вижу через консольное ведение журнала в моем серверном приложении. Но следующий выбор данных для заказов заканчивается использованием ранее установленного токена доступа, и это вызывает дополнительную несанкционированную ошибку с сервера API, поскольку запрос выполняется с недопустимым токеном.
Если я обновляю браузер снова, информация пользователя и заказы пользователя извлекаются с использованием обновленного токена из предыдущего потока промежуточного программного обеспечения.
Так что я не уверен, что здесь происходит, мне интересно, не проблема ли с проблемой req.session
не сохраняться в хранилище сеансов вовремя для следующего запроса?
У кого-нибудь есть идеи, что здесь происходит?
Благодаря
Update 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
Response Headers
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, 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
Response Headers
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:54:56 GMT; HttpOnly; Secure
Date: Fri, 13 May 2016 11:24:56 GMT
Connection: keep-alive
Content-Length: 0
Update 2
Я должен также упомянуть, я использую connect-mongo
для моего хранилища сеансов, я попытался использовать хранилище памяти по умолчанию, но такое же поведение существует.
Привет андрей, нет, как вызовы не делаются от клиента одновременно. Я использую обещания angularjs, а второй запрос на вызов на стороне клиента не получается, пока пользовательский запрос запроса пользователя не будет разрешен. Я добавил несколько обширных протоколов на стороне сервера и вижу, как входящие запросы от клиента обрабатываются один за другим, при этом токены обновляются между ними. Хотелось бы, чтобы это было так же просто, как то, что вы предложили! Спасибо – mindparse
, тогда я также могу предложить следующее сообщение: http://stackoverflow.com/questions/13090177/updating-cookie-session-in-express-not-registering-with-browser - установить флаг качения в true, чтобы заставить сеанс для обновления по каждому запросу (для обеспечения его кеширования) –
Спасибо, но у меня уже есть 'roll: true' set – mindparse