使用 OpenID 连接的节点快递

Posted

技术标签:

【中文标题】使用 OpenID 连接的节点快递【英文标题】:Node express with OpenID connect 【发布时间】:2020-11-28 18:26:28 【问题描述】:

我使用 this 库将 oidc 与 nodejs 一起使用

我需要的是:

    用户使用用户密码登录,或者数据已经是会话 cookie。这是调用我的应用根路由"/"

    我已经在authorisation server注册应用程序,身份验证服务器应该调用我的app/redirect

    我从身份验证服务器获取了 clientId 和客户端密码,并将其放入应用程序中。

    当用户登录时,身份验证服务器应该调用我的应用程序 redirect 路由。

    oidc 策略我需要得到tokenset.claims();tokenset.id_token用户令牌。,在重定向调用

应该有

response_type: 'code',

https://github.com/auth0/express-openid-connect#getting-started

问题是调用了getUser 函数(在调试应用程序时)但是我从req.session.userIdentity 得到userIdentity,即undefined,知道这里可能有什么问题吗?

我们有相同的旧实现,它使用 OIDC,它适用于相同的身份验证服务器和 clientid 和 secret。

  const  auth, requiresAuth  = require('express-openid-connect');
  const session = require('express-session');
  const bodyParser = require('body-parser');
    
    module.exports = async (app) => 
    
      const ClientId = process.env.CI;
      const ClientSecret = process.env.CS;
      const URL = process.env.S_URL;
    
      app.use(session(
         name: 'bat-auth',
         secret: 'cookie-secret',
      ));

      app.use(bodyParser.json());
      app.use(bodyParser.urlencoded( extended: true ));
    
      app.use(auth(
          clientSecret: ClientSecret,
          issuerBaseURL: `$URL`,
          clientID: ClientId,
          baseURL: process.env.REDT_URL,
          redirectUriPath: '/redirect',  //my app redirect route
          authorizationParams: 
           response_type: 'code',
           response_mode: 'form_post',
           scope: 'openid',
          ,
        async handleCallback(req, res, next) 
           req.session.openidTokens = req.openidTokens;
           console.log('---req.openidTokens', req.openidTokens);
           req.session.userIdentity = req.openidTokens.claims();
          next();
        ,
        async getUser(req) 
           return req.session.userIdentity;
        ,
      ));

  app.get('/', (req, res) => 
    const tokenSet = req.openid.makeTokenSet(req.session.openidTokens);
    console.log(`tokenset root: $tokenSet`);

    res.send(req.isAuthenticated() ? 'Logged in' : 'Logged out');
  );
  app.get('/redirect', async (req, res) => 
    const tokenSet = req.openid.makeTokenSet(req.session.openidTokens);
    console.log(`tokenset: $tokenSet`);
    console.log('redirect called');
    res.send('redirect called');
  );

我应该使用表单发布,最后,我需要从tokensetuser.id_token 获取?

这是我已经验证过的!

    来自身份验证服务器的 ClientID 来自身份验证服务器的 ClientSecret 配置身份验证服务器我的应用程序redirect路径,成功登录后应该调用我 我也有aud

顺便说一句,在调试应用程序时,它不会停止添加 handleCallback 函数,但它首先在 getUser 应用程序上停止,不知道可能是什么原因...

【问题讨论】:

你能改进一下这个问题吗?你想达到什么目标? @ToreNestenius - 按照我的要求,我用 stesp 更新了我的问题,现在更清楚了吗?如果有什么不清楚的地方请告诉我 redirectUriPath 不应该是:'/redirect'?前面有 /?当你应该使用绝对或相对 URL 时,你必须小心。我会检查使用 Fidder 之类的工具来捕获流量,然后在您的问题中添加失败的请求。 @ToreNestenius - 感谢您的提示,我也尝试了'/redirect',但仍然遇到同样的错误,还有其他想法吗?我的其他配置看起来还可以吗? 我会检查使用 Fidder 之类的工具来捕获流量,然后在您的问题中添加失败的请求。这样我们就可以更轻松地找出您在流程中卡住的位置。 【参考方案1】:

看起来您正在尝试从req.session.userIdentity 读取,但您从未在任何地方设置它。您正在设置 req.session.openidTokens

基于example code,您可能希望将您的handleCallback 函数修改为以下内容:

async handleCallback(req, res, next)
  req.session.openidTokens = req.openidTokens;
  console.log('---req.openidTokens', req.openidTokens);
  req.session.userIdentity = req.openidTokens.claims(); // <-- this is required to make your code sample work
  next();

【讨论】:

谢谢,我试了一下,它也不起作用,在调试应用程序时它不会在handleCallback 停止它只是在getUser 停止所以你提供的代码将不起作用,任何想法为什么它不停止? 知道如何进行吗? 我会逐字获取示例代码并验证它是否有效,然后进行小的增量更改,直到达到所需的状态。【参考方案2】:

看看你做了什么。你没有让人们回答你的问题变得太容易,你可以做更多的事情来改善你自己的自我诊断:

响应模式

去掉这个字段——我想我说得对,应该始终将授权响应设置为“查询”,这将是默认值。这可能会导致问题。

异步语法

我可能是错的,但我将从Auth0 page 的确切语法开始。有时我通过错误的语法在这方面犯了错误。

handleCallback: async function (req, res, next) 
    req.session.userIdentity = req.openidTokens.claims();
    next();
  ,

HTTP 调试

Tore 说您应该在此处跟踪消息并发布任何故障是 100% 正确的。作为消息外观的示例,请参阅我的blog post。这涵盖了客户端授权代码流 (PKCE) 而不是服务器端授权代码流,但消息非常相似。

这里更广泛的一点是,如果您不了解 OAuth 消息和令牌字段,您将经常被阻止,而不是能够诊断自己的问题。在您的情况下,也许第 7 步没有作为预期的查询参数返回,因此库失败了?

如何捕获 HTTP 消息

您能否按照与我的NodeJS API 相同的方式更新您的配置,方法是添加以下类型的配置,然后运行诸如 Fiddler 或 Charles 之类的工具。然后,您应该能够在您的 Web 后端和授权服务器之间捕获 OAuth 消息,然后将任何失败的消息发回此处:

auth(
  client_id: 'qhuefhuef',
  ...,
  httpOptions: 
    agent: TunnelAgent.httpsOverHttp(
      proxy: Url.parse('http://127.0.0.1:8888'),
    )
  

花点时间来完成这项工作是非常值得的,这将有利于该领域的所有未来发展。我的HTTP debugging write up 中有更多详细信息。

错误处理

另一种可能性是授权服务器在标准“错误”/“错误描述”字段中返回错误响应,而您没有处理它们。

一旦解决了眼前的问题,就不要满足。 OAuth 解决方案有多个移动部分,并且会出现间歇性问题,一旦您将应用部署到测试人员或生产环境,您将希望能够快速解决这些问题。

我始终建议在开发过程中使 OAuth 消息失败,然后确保您捕获正确的数据并控制 UI 错误报告。有关测试故障点的方法,请参阅我的文章的第 10 步和第 17 步。

【讨论】:

当我删除 response_mode 时,出现错误:Error: Response mode "form_post" is not supported by the issuer. Supported response modes are "query", "fragment". 因此我尝试使用 query,但我不确定它是否正确... response_mode = query 表示使用授权代码流时如何接收授权代码,如我所写的第 7 步所示。然后使用表单帖子将代码交换为令牌,但您没有指定。另请参阅section 4.1.2 of official specs。 最后我需要的是user.id_token 我已将其更改为仅使用:authorizationParams: scope: 'openid', ,,但仍然出现错误:Error: Response mode "form_post" is not supported by the issuer. Supported response modes are "query", "fragment". 我应该试试别的吗?

以上是关于使用 OpenID 连接的节点快递的主要内容,如果未能解决你的问题,请参考以下文章

如何使用可选参数创建端点? (节点、快递、MongoDB)

节点、快递、护照 - 更新记录后更新会话

使用 openid 连接重定向的反向代理

无法使用 axios 将 jwtToken 从反应客户端发送到节点/快递后端

javascript 使用节点http-proxy对快递应用程序的/ api进行代理

为啥我在上网几个小时后收到 503 错误?节点/快递