首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何通过passport-saml验证后重定向回最初请求的url?

如何通过passport-saml验证后重定向回最初请求的url?
EN

Stack Overflow用户
提问于 2014-07-07 07:11:19
回答 2查看 14.4K关注 0票数 31

如果这是一个愚蠢的问题,我很抱歉,但我在理解如何将客户端浏览器重定向回最初通过我们的SAML身份提供者(IdP)身份验证后请求的任何URL时遇到了一些问题。我使用的是最新版本的passport --saml、passport和express。

例如,假设客户机最初从另一个未受保护的页面上的链接请求/foo/bar,但因为这是一个受保护的资源,所以我用重定向到/login作为响应,在这里我调用passport.authenticate('saml')

代码语言:javascript
复制
app.get('/login', passport.authenticate('saml'));

function ensureAuth(req, res, next) {
    if (req.user.isAuthenticated()) {return next();}
    else {res.redirect('/login');}
}

app.get('/foo/bar', ensureAuth, function(req, res) {
    ...
});

该调用将把浏览器重定向到我的IdP的登录页面,在成功进行身份验证之后,IdP将回发到我的/login/callback路由。在此过程中,我再次使用passport.authenticate(saml)验证响应SAML,如果一切正常,则将浏览器重定向回所请求的resource...but。我如何知道所请求的资源是什么?因为这是一个POST回调,所以我丢失了与原始请求相关的所有状态。

代码语言:javascript
复制
app.post('/login/callback', passport.authenticate('saml'), function(req, res) {
    res.redirect('...can I know which url to redirect back to?...');
});

passport-saml readme中的示例只显示了一个硬编码的重定向回根资源,但我希望重定向回最初请求的URL (/foo/bar)。

我是否可以向IdP发送一个url或其他值,以便在响应SAML中往返并返回POSTed?如果是这样,我如何在我的/login/callback路由中访问它?

或者,有没有更好的,快递/护照的方式来做这件事,我错过了?

如果您能提供任何帮助,我们将不胜感激!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-14 23:50:23

我是否可以向IdP发送一个url或其他值,以便在响应

中往返并返回POSTed?如果是这样,我如何在我的/login/callback路由中访问它?

要通过IdP往返传递一个值,您需要使用RelayState。这是一个你可以发送给IdP的值,如果你这样做了,他们必须原封不动地把它发回。

以下是SAML specifications要说的话:

3.1.1 RelayState的使用

一些绑定定义了用于保存和传递状态信息的"RelayState“机制。当这种机制作为SAML协议的初始步骤用于传送请求消息时,它对随后用于传送响应的绑定的选择和使用提出了要求。也就是说,如果SAML请求消息伴随着RelayState数据,那么SAML响应器必须使用也支持RelayState机制的绑定返回其SAML协议响应,并且必须将它与请求一起接收的确切RelayState数据放入响应中相应的RelayState参数中。

要将其与passport-saml一起使用,必须将其添加为additionalParams值。下面的代码显示了这种情况。

代码语言:javascript
复制
saml = new SamlStrategy
    path: appConfig.passport.saml.path
    decryptionPvk: fs.readFileSync(appConfig.passport.saml.privateKeyFile)
    issuer: appConfig.passport.saml.issuer
    identifierFormat: tenant.strategy.identifierFormat
    entryPoint: tenant.strategy.entryPoint
    additionalParams:{'RelayState':tenant.key}
    ,
    (profile, next) -> 
        # get the user from the profile

上面的代码来自一个多租户saml实现,所以我将我的tenant.key作为RelayState参数发送。然后,我从IdP的POSTed返回值的主体中检索该值,并使用它重新建立所需的所有状态。

代码语言:javascript
复制
getTenantKey: (req, next) ->
    key = req.body?.RelayState ? routes.match(req.path).params.tenentKey
    next null, key

你的案子可能会更简单。您可能希望将最终目的地url存储在时间有限的缓存中,然后将缓存键作为RelayState参数发送。

无论如何,如果只使用原始的RelayState request-id作为缓存键,就可以完全避免使用SAML id。此值始终通过InResponseTo字段发回给您。

票数 26
EN

Stack Overflow用户

发布于 2017-10-04 08:02:16

如果您想在每个请求的基础上指定RelayState,您可能认为您可以这样做:

代码语言:javascript
复制
passport.authenticate('saml', { additionalParams: { RelayState: "foo" } })

但这并不管用。如果您查看实现:https://github.com/bergie/passport-saml/blob/6d1215bf96e9e352c25e92d282cba513ed8e876c/lib/passport-saml/saml.js#L326,您将看到additionParams是从初始配置选项或从req对象(而不是从每个请求选项)中选取的。

但幸运的是,Passport SAML策略针对每个请求执行此操作:

代码语言:javascript
复制
var RelayState = req.query && req.query.RelayState || req.body && req.body.RelayState;

然后,它在配置选项中查找更多(全局) additionalParams。

因此,如果您希望针对每个请求指定RelayParams,则必须在调用authorize之前将它们加载到请求中。在我的例子中,我在路由处理程序中执行如下操作:

代码语言:javascript
复制
req.query.RelayState = req.params.redirect_to;
passport.authenticate('saml')(req, res, next);

然后,当重定向的请求从SAML返回时,您应该能够使用req.body.RelayParams来访问每个请求的状态。

请注意,如果您的RelayParams值是一个对象,则可能必须使用JSON.stringify将其编码为RelayParams,并使用JSON.parse将其解码出来(在我的示例中,我必须这样做)。

票数 20
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24601188

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档