TL;DR
如何拦截请求,为ID选择不同的路由,将ID存储在会话中,然后使用刚获得的ID继续原始请求(特别是PUT/POST )?
背景
我使用HapiJS (8)将客户端的请求代理到现有的API (在那里,我无法控制进程/逻辑)。API要求每个请求在查询字符串或有效负载中包含一个“会话ID”(取决于http方法)。为了得到会话ID,我要做的就是要一个.不需要用户名/pwd(它在头中使用基本auth )。如果不更新会话ID,则每24小时过期一次。每个客户端都有自己的会话ID。
我目前正在使用哈皮饼干来存储会话ID的值,在需要ID时会查询该值。如果ID过期或null,我需要在客户端的请求成功地代理到API之前请求一个新的ID。
电流溶液
当客户端的请求方法是“GET”时,我很好地利用了在appendNext中描述的appendNext配置来处理这个挑战。请求被hapi-auth-cookie拦截,如果需要一个新的会话ID,则将请求发送到该特定路由以获得请求,API返回分配给Hapi会话的ID,然后(使用沉船)一个reply.redirect返回原始的get请求,在它完成该请求时。天衣无缝,优雅。
但是,我不知道如何使用包含数据有效负载的不同http方法来实现相同的流。
除了reply.redirect之外,还有什么东西可以在维护原始有效载荷和方法的同时实现相同的目标吗?还是总体上有更好的方法来做到这一点?
代码(用于当前用于“GET”请求的内容)
主应用程序文件(hapi-auth-cookie信托)
# register plugins
server.register require('./plugins')
, (err) ->
throw err if err
# set authentication (NLS) configs
server.auth.strategy 'session', 'cookie',
password: 'session_pwd'
cookie: 'ghsid'
redirectTo: '/api/SessionID' #get new session ID
isSecure: config.get 'ssl'
appendNext: true
ttl: config.get 'session_length'利用会话身份验证并调用hapi插件的控制器:
simpleRequest:
auth: 'session'
handler: (request, reply) ->
qs = Qs.stringify request.query
request.papi_url = "/api/route/sample?#{qs}"
reply.proxy
mapUri: (request, reply) ->
auth = config.get 'basic_auth'
api_host = config.get 'api_host'
papi_url = request.papi_url
path = api_host + papi_url
next null, path, {authorization: auth}获取新会话ID的路由
module.exports = [
{
path: '/api/SessionID'
method: 'GET'
config: SessionController.session
}
]会话控制器
Wreck = require 'wreck'
config = require 'config'
module.exports =
session:
description: 'Get new session ID'
auth:
mode: 'try'
strategy: 'session'
plugins:
'hapi-auth-cookie':
redirectTo: false
handler: (request, reply) ->
# request configs
papi_url = "/Session"
api_host = config.get 'api_host'
url = api_host + papi_url
opts =
headers:
'Authorization': config.get 'basic_auth'
'content-type': 'application/json;charset=UTF-8'
# make request to PAPI
Wreck.post url, opts, (err, res, body) ->
throw new Error err if err
try
bdy = JSON.parse body
sess =
nls: bdy.SessionId
if bdy.SessionId
# authenticate user with NLS
request.auth.session.set sess
# redirect to initial route
reply.redirect request.url.query.next
else
return throw new Error
catch err
throw new Error err最终解
基于Matt的回答,我创建了一个自定义插件,它被注册为身份验证方案,这样我就可以控制每个路由。
下面是插件代码:
Wreck = require 'wreck'
config = require 'config'
exports.register = (server, options, next) ->
server.auth.scheme 'cookie', internals.implementation
next()
exports.register.attributes =
name: 'Hapi Session Interceptor'
version: '1.0.0'
internals = {}
internals.implementation = (server, options, next) ->
scheme = authenticate: (request, reply) ->
validate = ->
session = request.state.sessionID
unless session
return unauthenticated()
reply.continue(credentials: {'session': session})
unauthenticated = ->
api_url = "/SessionID"
api_host = config.get 'api_host'
url = api_host + api_url
opts =
headers:
'Authorization': config.get 'basic_auth'
'content-type': 'application/json;charset=UTF-8'
# make request to API
Wreck.post url, opts, (err, res, body) ->
throw new Error err if err
bdy = JSON.parse body
sess =
session: bdy.SessionId
if bdy.SessionId
reply.state 'sessionID', bdy.SessionId
reply.continue(credentials: sess)
else
return throw new Error
validate()
return scheme发布于 2015-03-10 21:05:47
虽然我并不完全忠实于您的代码,但我已经列出了一个示例,其中包含了我认为您正在使用的所有部分。
我制作了一个service插件来表示您的API。upstream插件表示您要代理的实际上游API。
所有请求都通过service传递并代理到upstream,upstream只输出它接收到的所有头和有效负载。
如果原始请求不包含带有sessionId的cookie,则会在upstream上命中一条路径以获得该路径。然后,当响应返回流时,使用此值设置cookie。
代码在这里:https://github.com/mtharrison/hapijs-proxy-trouble
用卷发和你的浏览器试试。
GET: curl http://localhost:4000
POST W/有效载荷: curl -X POST -H "content-type: application/json" -d '{"example":"payload"}' http://localhost:4000
index.js
var Hapi = require('hapi');
var server = new Hapi.Server();
server.connection({ port: 4000, labels: ['service'] }); // Your service
server.connection({ port: 5000, labels: ['upstream']}); // Pretend upstream API
server.state('session', {
ttl: 24 * 60 * 60 * 1000,
isSecure: false,
path: '/',
encoding: 'base64json'
});
server.register([{
register: require('./service')
}, {
register: require('./upstream')
}],
function (err) {
if (err) {
throw err;
}
server.start(function () {
console.log('Started!');
});
});service.js
var Wreck = require('wreck');
exports.register = function (server, options, next) {
// This is where the magic happens!
server.select('service').ext('onPreHandler', function (request, reply) {
var sessionId = request.state.session;
var _done = function () {
// Set the cookie and proceed to the route
request.headers['X-Session-Id'] = sessionId;
reply.state('session', sessionId);
reply.continue();
}
if (typeof sessionId !== 'undefined')
return _done();
// We don't have a sessionId, let's get one
Wreck.get('http://localhost:5000/sessionId', {json: true}, function (err, res, payload) {
if(err) {
throw err;
}
sessionId = payload.id;
_done();
});
});
server.select('service').route({
method: '*',
path: '/{p*}', // Proxies all routes and methods
handler: {
proxy: {
host: 'localhost',
port: 5000,
protocol: 'http',
passThrough: true
}
}
});
next();
};
exports.register.attributes = {
name: 'your-service'
};upstream.js
exports.register = function (server, options, next) {
server.select('upstream').route([{
method: '*',
path: '/{p*}',
handler: function (request, reply) {
// Just prints out what it received for headers and payload
// To prove we got send the original payload and the sessionID header
reply({
originalHeaders: request.headers,
originalPayload: request.payload,
})
}
}, {
method: 'GET',
path: '/sessionId',
handler: function (request, reply) {
// Returns a random session id
reply({ id: (Math.floor(Math.random() * 1000)) });
}
}]);
next();
};
exports.register.attributes = {
name: 'upstream'
};https://stackoverflow.com/questions/28949559
复制相似问题