【问题标题】:Validate Azure Bearer Token from Frontend on Net Core WebApi Backend从 Net Core WebApi 后端的前端验证 Azure 不记名令牌
【发布时间】:2020-08-18 20:30:08
【问题描述】:

目标:使用 Microsoft 登录对话框在前端登录 Azure AD 用户。将令牌附加到后端请求。在后端验证令牌以确保只有授权用户才能访问代码。棘手的部分:手动验证,因为它不是唯一的身份验证。

我已成功登录并发送令牌,但在验证时出现如下错误:IDX10511: Signature validation failed. Keys tried: ...

这是我目前所拥有的:

app.module.ts

@NgModule({
  declarations: [
    AppComponent,
    RestrictedPageComponent
  ],
  imports: [
    HttpClientModule,
    MsalModule.forRoot({
      auth: {
        clientId: '<CLIENT ID>',
      }
    }, {
      consentScopes: [
        'user.read',
        'openid',
        'profile',
      ],
      protectedResourceMap: [
        ['https://localhost:44323/v1/login', ['user.read']], // frontend
        ['https://localhost:5001/api/Login', ['user.read']] // backend
      ]
    }),
    BrowserModule,
    AppRoutingModule
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: MsalInterceptor,
      multi: true
    },
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

login.component.ts

  login() {
    const loginRequest = { scopes: ['https://graph.microsoft.com/User.ReadWrite'] };
    this.authService.loginPopup(loginRequest);
  }

这似乎工作得很好。我可以通过 Microsoft 登录,然后 MsalInterceptor 将不记名令牌添加到后端请求标头。

在后端,我现在只想验证令牌是否有效以及用户是否通过了正确的身份验证。

private JwtSecurityToken Validate(string token)
{
    var stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
    // also tried "https://login.microsoftonline.com/<TENANT ID>/v2.0/.well-known/openid-configuration"

    var openIdConnectConfigurationRetriever = new OpenIdConnectConfigurationRetriever();
    var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, openIdConnectConfigurationRetriever);

    var config = configManager.GetConfigurationAsync().Result;

    var validationParameters = new TokenValidationParameters
    {
        IssuerSigningKeys = config.SigningKeys,

        // just for now
        ValidateAudience = false,
        ValidateIssuer = false,
        ValidateLifetime = false
    };

    var tokenHandler = new JwtSecurityTokenHandler();
    IdentityModelEventSource.ShowPII = true;

    token = token.Replace("Bearer ", string.Empty); // weird - the token starts with "Bearer " and is not valid like this
    var result = tokenHandler.ValidateToken(token, validationParameters, out var jwt);

    return jwt as JwtSecurityToken;
}

在调用tokenHandler.ValidateToken(... 时,我总是收到类似IDX10511: Signature validation failed. Keys tried: ... 的错误。 我不确定我是否正确理解并使用了整个概念。 我对 Azure Bearer 令牌的使用和验证的了解越多,我就越感到困惑。

我可以解析http://jwt.io 上的令牌,但签名始终无效。

后端能否在不传递任何共享密钥或客户端 ID 的情况下验证令牌? 这是开始的正确方法吗?

编辑:我不确定我是否使用了正确的端点来调用前端和后端以及不同端点扮演的角色(例如:有或没有租户 ID)。如果有人能解释一下就好了。

BR马蒂亚斯

【问题讨论】:

  • 请参阅下面的答案。仅此外:对于手动令牌验证,我必须将 stsDiscoveryEndpoint 更改为 https://login.microsoftonline.com/&lt;TENANT ID&gt;/v2.0/.well-known/openid-configuration

标签: asp.net-core azure-active-directory microsoft-graph-api bearer-token


【解决方案1】:

您的前端似乎正在获取 Microsoft Graph API 的访问令牌。 该令牌仅适用于 MS Graph API,而不适用于您的 API。 这些 Graph API 令牌的构建方式也很特殊,您不应尝试验证它们。

相反,您需要在前端指定 API 的范围。

      consentScopes: [
        'your-api-client-id-or-app-id-uri/user_impersonation',
        'openid',
        'profile',
      ],
      protectedResourceMap: [
        ['https://localhost:44323/v1/login', ['user.read']], // frontend
        ['https://localhost:5001/api/Login', ['your-api-client-id-or-app-id-uri/user_impersonation']] // backend
      ]

为此,您需要转至 Azure AD 中 API 的应用注册,转至公开 API 选项卡,然后在此处添加范围。 然后获取完整的范围 ID(包括您的 API 客户端 ID 或应用 ID URI + 范围 ID),并在获取令牌时将其用作范围。 然后,Azure AD 应该为您提供一个用于您的 API 的令牌。

如果您使用的是 ASP.NET Core,验证 Azure AD 令牌所需的最低配置是:

// In ConfigureServices
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(o =>
    {
        o.Authority = "https://login.microsoftonline.com/your-tenant-id";
        o.Audience = "your-app-client-id";
    });

// In Configure (between UseRouting and UseEndpoints)
app.UseAuthentication();
app.UseAuthorization();

现在,在某些情况下,如果您的 API 配置为在 Azure AD 中接收 v1 令牌,则该令牌可能包含 API 客户端 ID 或应用 ID URI。 在这种情况下,您可以配置多个有效受众:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(o =>
    {
        o.Authority = "https://login.microsoftonline.com/your-tenant-id";
        o.TokenValidationParameters = new TokenValidationParameters
        {
            ValidAudiences = new[]
            {
                "your-api-client-id",
                "your-api-app-id-uri"
            }
        };
    })

【讨论】:

  • 非常感谢!当必须在 Azure AD 中注册 API 时,我还可以在 localhost 上运行它吗?另外:我不能将令牌与service.AddAuthentications(..) 一起使用,因为我们对某些主要区域进行了其他身份验证。那么,我可以在原始帖子中验证后端的令牌吗?那么我将如何传递租户 ID 和应用客户端 ID?
  • 是的,当然你也可以在 localhost 中运行它 :) API 真的不需要任何特殊配置就可以在本地工作,因为它们不使用重定向 URL。
  • 您可以为您的应用添加多种认证方案,无需自行验证:docs.microsoft.com/en-us/aspnet/core/security/authorization/…。您可以按照他们在文档中的建议(使用授权策略来定义要使用的方案),或者注册两者并在默认方案上定义 ForwardDefaultSelector。在此回调中,您可以检查请求是否包含 JWT 标头。如果是这样,将该请求的默认方案更改为 JWT 身份验证。
猜你喜欢
  • 2018-07-09
  • 2018-09-21
  • 1970-01-01
  • 2018-08-03
  • 1970-01-01
  • 2019-03-23
  • 2020-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多