asp.net-core - 从 Net Core WebApi 后端的前端验证 Azure Bearer token

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

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

我已成功登录并发送 token ,但在验证时出现如下错误:IDX10511:签名验证失败。尝试过的按键:...

这是我到目前为止所拥有的:

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 将不记名 token 添加到后端请求 header 。

在后端,我现在只想验证 token 是否有效以及用户是否经过正确身份验证。

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: Signaturevalidation failed. Keys attempts: ... 的错误。 我不再确定我是否正确理解和使用了整个概念。 我对 Azure Bearer token 的使用和验证了解得越多,它就越让我困惑。

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

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

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

BR 马蒂亚斯

最佳答案

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

相反,您需要在前端指定 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),并在获取 token 时将其用作范围。 然后,Azure AD 应该为您提供一个适用于您的 API 的 token 。

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

// 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 token ,则该 token 可能包含 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"
            }
        };
    })

关于asp.net-core - 从 Net Core WebApi 后端的前端验证 Azure Bearer token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61591804/

相关文章:

nginx - Nginx 背后的 SignalR - 获得 200 响应而不是 websocket 升级

c# - 是否可以在命令行或通过配置文件添加 "InternalsVisibleTo"的包?

asp.net-core - Autofac 依赖解析异常

azure - 通过 powershell 使用 MFA 以编程方式对 AAD 进行身份验证

microsoft-graph-api - Microsoft Graph API,仅应用权限

c# - 在 Configure() 之后启动 IHostedService

azure - 从 Google 服务帐户模拟 Azure 服务主体

c# - 具有 Azure Active Directory 的 Web 应用程序始终重定向到 '~/.auth/login/done' URL

azure - 过滤子句无效。微软Graph

azure - 如何添加管理员帐户以向我的 Azure AD 应用程序授予静态权限?