具有IS4的azure .net核心应用:Web api调用失败,并显示“承载者错误= invalid_token颁发者无效”

时间:2020-11-12 18:29:41

标签: azure docker azure-web-app-service identityserver4 nswag

我有一个 .net Core 3.1 应用程序,该应用程序在Azure Web应用程序中运行,用于容器(linux)服务。此应用程序是一个Web API项目,前端为角度9 。它使用身份服务器4 进行授权。

作为参考,我在项目中使用了这个clean architecture framework template(添加docker support pr)。

该应用程序可以在服务中正常运行。前端工作正常,我可以使用ID4“登录”,并且可以看到登录时返回了授权令牌。

问题:

当我从前端角度客户端应用程序调用后端Web API时,出现以下错误:

HTTP/1.1 401 Unauthorized
Server: Kestrel
WWW-Authenticate: Bearer error="invalid_token", error_description="The issuer 'https://*********.azurewebsites.net' is invalid"

我很想为 IssuerUri 添加手动设置,但是identity server 4 docs建议不要这样做,所以我没有这样做。也许在docker中运行此命令会有所不同。

根据these docs for proxy load balancers.,我确实必须添加对转发头的支持,以使IS4在 startup.cs configureServices 中正常工作,我必须在应用程序设置中添加ASPNETCORE_FORWARDEDHEADERS_ENABLED = true

当我比较请求的提琴手结果时,可以看到 AspNetCore.Antiforgery 与登录和Web api调用相同,但 .AspNetCore.Identity.Application >值不同。

我正在使用 nSwag 自动生成对angular的api服务调用(如果有所不同)。

问题:

有人可以帮我弄清楚为什么我可以登录但所有网络api请求都失败,并出现上述未授权错误吗?

先谢谢。 JK

修改1

我使用了提琴手来获取请求的授权令牌,并使用jwt.io对其进行了解析。 iss值与app / web api相同:

"iss": "https://******.azurewebsites.net", 

IS4使用此域登录,并且正常工作。如果该值正确,那么还有另一件事可能是错误的吗?

编辑2:

只是为了获得更多背景信息。

我的应用在statup.cs中使用配置

app.UseHsts();
app.UseHttpsRedirection();

因此,我需要添加以下代码,以确保在应用程序服务对TSL,负载平衡器/代理和我的Docker容器(starup.cs ConfigureServices)的处理之间的请求中转发标头:

// the following is documented here:
// https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1#forward-the-scheme-for-linux-and-non-iis-reverse-proxies-1
// it is needed to run kestrel in azure app service in http with header forwarding
if (string.Equals(
    Environment.GetEnvironmentVariable("ASPNETCORE_FORWARDEDHEADERS_ENABLED"),
    "true", StringComparison.OrdinalIgnoreCase))
{
    services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                   ForwardedHeaders.XForwardedProto;
        // Only loopback proxies are allowed by default.
        // Clear that restriction because forwarders are enabled by explicit 
        // configuration.
        options.KnownNetworks.Clear();
        options.KnownProxies.Clear();
    });
}

我在日志中收到以下错误,确认了与发卡行不匹配相同的错误

Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDX10205:发行者验证失败。发行者:'[PII隐藏。欲了解更多 详细信息,请参见https://aka.ms/IdentityModel/PII。]”。不匹配: validationParameters.ValidIssuer ...

我为Jwt令牌使用了以下默认设置:

 services.AddAuthentication().AddIdentityServerJwt();

如果我导航到 https://*******.azurewebsites.net/.well-known/openid-configuration/jwks ,则我的OIDC将获得以下JSON设置设置:

{
  "issuer": "https://*******.azurewebsites.net",
  "jwks_uri": "https://*******.azurewebsites.net/.well-known/openid-configuration/jwks",
  "authorization_endpoint": "https://*******.azurewebsites.net/connect/authorize",
  "token_endpoint": "https://*******.azurewebsites.net/connect/token",
  "userinfo_endpoint": "https://*******.azurewebsites.net/connect/userinfo",
  "end_session_endpoint": "https://*******.azurewebsites.net/connect/endsession",
  "check_session_iframe": "https://*******.azurewebsites.net/connect/checksession",
  "revocation_endpoint": "https://*******.azurewebsites.net/connect/revocation",
  "introspection_endpoint": "https://*******.azurewebsites.net/connect/introspect",
  "device_authorization_endpoint": "https://*******.azurewebsites.net/connect/deviceauthorization",
  "frontchannel_logout_supported": true,
  "frontchannel_logout_session_supported": true,
  "backchannel_logout_supported": true,
  "backchannel_logout_session_supported": true,
  "scopes_supported": [
    "openid",
    "profile",
    "CleanArchitecture.WebUIAPI",
    "offline_access"
  ],
  "claims_supported": [
    "sub",
    "name",
    ....
    "updated_at"
  ],
  "grant_types_supported": [
    "authorization_code",
    "client_credentials",
    "refresh_token",
    "implicit",
    "password",
    "urn:ietf:params:oauth:grant-type:device_code"
  ],
  "response_types_supported": [
    "code",
    "token",
    "id_token",
    "id_token token",
    "code id_token",
    "code token",
    "code id_token token"
  ],
  "response_modes_supported": ["form_post", "query", "fragment"],
  "token_endpoint_auth_methods_supported": [
    "client_secret_basic",
    "client_secret_post"
  ],
  "id_token_signing_alg_values_supported": ["RS256"],
  "subject_types_supported": ["public"],
  "code_challenge_methods_supported": ["plain", "S256"],
  "request_parameter_supported": true
}

我在本文档中比较了发卡行,它们与令牌中的发卡行相同,如上所示。

我仍然不确定如何调试它以找出发行方不匹配的地方。

注意:我将范围缩小了一点。内置/默认IS4端点的所有调用均有效。它是我在控制器中定义的唯一自定义webAPI端点,无法正确验证令牌。

任何具有[Authorize]属性的webAPI端点都会因无效的颁发者而失败

编辑3:

感谢@d_f评论,我将IS4文档用于adding local API 我在startu.ca configure services中的服务初始化中添加了以下调用:

services.AddIdentityServer().AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddLocalApiAuthentication();  // I added this line after the above line

然后我将webAPI控制器顶部的 [Authorize] 属性更改为:

//[Authorize]
[Authorize(IdentityServerConstants.LocalApi.PolicyName)]

但是,我仍然遇到相同的错误。仅在我的自定义webAPI端点上,IS4端点均可使用。登录有效,但没有具有[Authorize]属性的任何Web api端点。

编辑4:

我删除了上述设置并更改了我的服务。AddAUthentication()添加到以下内容:

services.AddAuthentication()
    .AddIdentityServerJwt()
    .AddLocalApi(options =>
        options.ExpectedScope = "IdentityServer4");

我也尝试过:

services.AddAuthentication()
    .AddIdentityServerJwt()
    .AddLocalApi();

我使用了策略名称“ IdentityServer4”,因为它似乎是IS4中的默认策略

这是整个上下文的样子:

services.AddDefaultIdentity<ApplicationUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

services.AddAuthentication()
    .AddIdentityServerJwt() 
    .AddLocalApi(options =>
        options.ExpectedScope = "IdentityServer4");

在所有这些变体中,这在我的计算机上本地运行。恰好在azure Web应用程序的容器中运行它时,我得到了自定义webAPI端点的颁发者失败。

解决方案:

由于这里提供了所有帮助,我找到了解决方案。开箱即用的IS4尝试自动设置 ISS /颁发者。这可以在本地运行,但在我的生产环境中,我的容器在用于容器的Azure Web应用程序中运行。 Azure将我的容器放在另一个容器中以进行负载平衡/代理,以处理https加密。结果,在我的容器中自动检测到的IS4发行者与Azure Web应用程序URL之间存在差异。

通过在我的代码中手动设置发行者,错误消失并且一切正常。

您可以在两个地方执行此操作

  1. 在您的appsettings.jsson中,例如:
     "IdentityServer": {
        "IssuerUri": "https://yourapp.azurewebsites.net", 
  1. 或类似这样的代码:
      services.AddIdentityServer(options =>
                {
                    options.IssuerUri = "https://your.azurewebsites.net/";
                })
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

希望这对其他人有帮助,并再次感谢所有在此提供帮助的人

2 个答案:

答案 0 :(得分:1)

您需要捕获令牌并使用https://jwt.ms对其进行解析。

根据您的错误消息:invalid token The issuer is invalid,因此您应该检查令牌中的iss声明,以确保它与API中期望的相同。参见here

enter image description here

答案 1 :(得分:0)

解决方案:

由于这里提供了所有帮助,我找到了解决方案。开箱即用的IS4尝试自动设置 ISS /颁发者。这可以在本地运行,但在我的生产环境中,我的容器在用于容器的Azure Web应用程序中运行。 Azure将我的容器放在另一个容器中以进行负载平衡/代理,以处理https加密。结果,在我的容器中自动检测到的IS4发行者与Azure Web应用程序URL之间存在差异。

通过在我的代码中手动设置发行者,错误消失并且一切正常。

您可以在两个地方执行此操作

  1. 在您的appsettings.jsson中,例如:
     "IdentityServer": {
        "IssuerUri": "https://yourapp.azurewebsites.net", 
  1. 或类似这样的代码:
      services.AddIdentityServer(options =>
                {
                    options.IssuerUri = "https://your.azurewebsites.net/";
                })
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

希望这对其他人有帮助,并再次感谢所有在此提供帮助的人