使用 Microsoft.Identity.Web 从 AzureAD 验证 JWT 成功,但在同一调用中失败

发布于 2025-01-09 10:38:24 字数 2702 浏览 1 评论 0原文

我有一个 API,需要使用 AzureAD 进行保护,以便它可以使用 SSO。

该 API 有一个 Swagger UI,所以我(在阅读了很多很多教程/解释/问题之后):

  • 在 Azure 中创建了应用程序注册
  • 为我的 API 创建了范围
  • 将我的范围添加为 API 权限
  • 将“accessTokenAcceptedVersion”更改为 2清单
  • 将 Swagger 设置为使用具有适当配置和值的 OAuth2 流
  • 登录到单个租户

使用 Microsoft.Identity.Web 设置 API 并添加配置以允许按照以下方式 :https://github.com/AzureAD/microsoft-identity-web/wiki/ web-apis,API中的设置如下:

builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration, subscribeToJwtBearerMiddlewareDiagnosticsEvents: true);

appsettings.json:

{
   ...
   "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "TenantId": "{guid for tenant ID from Azure portal}",
        "ClientId": "{guid for client ID from Azure portal}",
        "CallbackPath": "/signin-oidc",
        "SignedOutCallbackPath ": "/signout-callback-oidc"
    }
}

我现在在swagger上有了授权按钮。

当我单击该按钮时,我会看到一个对话框:

Swagger Auth Dialog

输入客户端 ID,选择范围并单击授权。 Azure AD 登录窗口会在新选项卡中打开,输入凭据并提交,然后我们会重定向回 swagger,并且我们已获得授权:

Authorized

到目前为止一切顺利。

然后,我尝试调用 API 本身,但失败并显示 401。

检查请求,我可以看到 JWT 令牌作为不记名令牌传递。

因此,我在 JwtBearerMiddlewareDiagnostics 中设置了一些断点,尝试找出问题所在。

以下事件按以下顺序触发:

  • OnMessageReceivedAsync
  • OnTokenValidatedAsync - 使用 IsAuthenticated:true
  • OnChallengeAysnc - 使用 IsAuthenticated: false 和 AuthenticationFailure: null

作为比较,如果我让 JWT 过期,我会得到:

  • OnMessageReceivedAsync
  • OnAuthenticationFailedAsync - 带有 IsAuthenticated: false
  • OnChallengeAsync - 带有 IsAuthenticated: false 和 < code>AuthenticationFailure:“有关令牌已过期的一些消息”

因此,我正在努力解决的是,当我的 JWT 有效时,OnTokenValidatedAsync 会触发并显示有效的UserPrinciple,其中身份显示用户已通过验证。但几乎在那之后,身份验证质询会触发,其中 UserPrinciple 显示用户经过验证...然后因为我没有验证处理 OnChallengeAsync 事件时,会返回 401。我的理解是,如果没有有效令牌(在 JWT 流中),则会调用 OnChallengeAsync,但调用 OnTokenValidatedAsync 会显示令牌已正确传递且用户有效?!

此外,当我遇到“有效失败”(令牌已过期)时,传递给 OnChallengeAsync 的上下文清楚地显示了 AuthenticationFailure 属性中的原因,但当 OnChallengeAsync 为我的(据我所知)好的令牌触发,AuthenticationFailure 为 null...

I have an API that I need to secure with AzureAD so that it can use SSO.

The API has a Swagger UI, so I have (after reading many, many tutorials/explanations/issues):

  • Created an App Registration in Azure
  • Created a scope for my API
  • Added my scope as an API permission
  • Changed the "accessTokenAcceptedVersion" to 2 in the manifest
  • Set up Swagger to use the OAuth2 flow with appropriate config and values
  • Set up the API using Microsoft.Identity.Web and added configuration to allow sign-in to a single tenant

as per: https://github.com/AzureAD/microsoft-identity-web/wiki/web-apis, setup in the API is as follows:

builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration, subscribeToJwtBearerMiddlewareDiagnosticsEvents: true);

appsettings.json:

{
   ...
   "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "TenantId": "{guid for tenant ID from Azure portal}",
        "ClientId": "{guid for client ID from Azure portal}",
        "CallbackPath": "/signin-oidc",
        "SignedOutCallbackPath ": "/signout-callback-oidc"
    }
}

I now have the authorize button on swagger.

When I click the button I get a dialog:

Swagger Auth Dialog

Enter the client id, select the scope and click authorize. Azure AD sign-in window opens in a new tab, enter creds and submit, then we get redirected back to swagger, and we're authorized:

Authorized

So far so good.

I then try to call the API itself and it fails with a 401.

Checking the request I can see the JWT token being passed as a Bearer token.

So I stuck some breakpoints in JwtBearerMiddlewareDiagnostics to try and work out what is going wrong.

The following events fire in the following order:

  • OnMessageReceivedAsync
  • OnTokenValidatedAsync - with IsAuthenticated: true
  • OnChallengeAysnc - with IsAuthenticated: false, and AuthenticationFailure: null

As a comparison, if I let the JWT expire, I get:

  • OnMessageReceivedAsync
  • OnAuthenticationFailedAsync - with IsAuthenticated: false
  • OnChallengeAsync - with IsAuthenticated: false and AuthenticationFailure: "some message about the token being expired"

So, what I'm struggling with, is when my JWT is valid, OnTokenValidatedAsync fires and shows a valid UserPrinciple where the Identity shows that the user is validated.. but then almost immediately after that, an auth challenge fires where the UserPrinciple shows that the user is not validated... and then since I'm not handling the OnChallengeAsync event, a 401 is returned. My understanding is that OnChallengeAsync is called if there is no valid token (in a JWT flow), yet OnTokenValidatedAsync is called showing that the token was correctly passed and the user is valid?!

Also, when I have a "valid failure" (the token has expired), the context passed to OnChallengeAsync clearly shows the reason in the AuthenticationFailure property, yet when OnChallengeAsync fires for my (as far as I can tell) good token, AuthenticationFailure is null...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

流年里的时光 2025-01-16 10:38:24

终于找到问题了。

我缺少 app.UseAuthentication();。添加该行可以解决问题并且按预期工作:)

Finally found the issue.

I was missing app.UseAuthentication();. Adding that line, fixes the issue and it works as expected :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文