如何在STS Asp.Net 2.2项目+ Api Asp.Net 2.2项目+ angular7客户端中正确保护API

时间:2019-02-14 17:15:25

标签: identityserver4

已经为此苦苦挣扎了一段时间,让angular7客户端访问id4 Asp.Net core 2.2项目登录并返回jwt没问题,与angular7客户端访问Asp.Net core 2.2 api项目受保护的api都在下面id4保护。

jwt.io解码(值x'd出):

HEADER:ALGORITHM & TOKEN TYPE


{
  "alg": "RS256",
  "kid": "c672fc19f3ff652c5c8816cfac31bfcc",
  "typ": "JWT"
}
PAYLOAD:DATA


{
  "nbf": 1550161736,
  "exp": 1550164736,
  "iss": "https://localhost:44340",
  "aud": "angularclient",
  "nonce": "N0.88924643059608991550161727071",
  "iat": 1550161736,
  "at_hash": "A3fYyAynZIUQN5Z3ugvpvw",
  "sid": "90c459301964e9f136a38b9b19d9b1e0",
  "sub": "71765055-647D-432E-AFB6-0F84218D0247",
  "auth_time": 1550161731,
  "idp": "local",
  "preferred_username": "xxxxxxxx",
  "name": "xxxxxxxxxx",
  "regid": "xxxxxxxxx",
  "jseg": "xxxxx",
  "jobid": "xxxxx",
  "role": "xxxx",
  "given_name": "xxxx",
  "family_name": "Grexxxxenwald",
  "email": "xxxxx",
  "amr": [
    "pwd"
  ]
}

ID4配置:

private static readonly string[] customClaimTypes = { "role", "jseg", "jobid", "regid", "api1" };

        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResources.Email(),
                new IdentityResource("api1scope", customClaimTypes),
            };
        }

        public static IEnumerable<ApiResource> GetApis()
        {
            return new ApiResource[]
            {
                new ApiResource()
                {
                    Name = "api1",
                    Description = "tsicApis",
                    ApiSecrets =
                    {
                        new Secret(Startup.Configuration.GetSection("StsConfig:STSTSICApisSecuredSecret").Value.Sha256())
                    },
                    Scopes =
                    {
                        new Scope()
                        {
                            Name = "api1",
                            DisplayName = "Scope for the api1 ApiResource",
                        },
                    },
                    UserClaims = customClaimTypes
                }
            };
        }

        // clients want to access resources (aka scopes)
        public static IEnumerable<Client> GetClients()
        {
            var trustedClientSecrets = Startup.Configuration.GetSection("StsConfig:TrustedClientSecrets").Value;

            var angularClientUrl = Startup.Configuration.GetSection("StsConfig:AngularClientUrl").Value;
            var angularRedirectUris = Startup.Configuration.GetSection("StsConfig:AngularRedirectUris").Value;
            var angularPostLogoutRedirectUris = Startup.Configuration.GetSection("StsConfig:AngularPostLogoutRedirectUris").Value;
            var angularAllowedCorsOrigins = Startup.Configuration.GetSection("StsConfig:AngularAllowedCorsOrigins").Value;
            var angularClientSecret = Startup.Configuration.GetSection("StsConfig:STSTSICApisSecuredSecret").Value;

            var mvcClientSecrets = Startup.Configuration.GetSection("StsConfig:MVCClientSecrets").Value;
            var mvcRedirectUris = Startup.Configuration.GetSection("StsConfig:MVCRedirectUris").Value;
            var mvcFrontChannelLogoutUri = Startup.Configuration.GetSection("StsConfig:MVCFrontChannelLogoutUri").Value;
            var mvcPostLogoutRedirectUris = Startup.Configuration.GetSection("StsConfig:MVCPostLogoutRedirectUris").Value;


            // client credentials client
            return new List<Client>
            {
                new Client
                {
                    ClientName = "angularclient",
                    ClientId = "angularclient",
                    RequireClientSecret = true,
                    ClientSecrets = { new Secret(angularClientSecret) },

                    RequireConsent = true,
                    AllowRememberConsent = false,

                    AccessTokenType = AccessTokenType.Jwt,
                    AlwaysIncludeUserClaimsInIdToken = true,
                    AccessTokenLifetime = 33000,// 330 seconds, default 60 minutes
                    IdentityTokenLifetime = 3000,
                    AllowAccessTokensViaBrowser = true,

                    AllowedGrantTypes = GrantTypes.Implicit,
                    AllowedCorsOrigins = angularAllowedCorsOrigins.Split(','),
                    AllowedScopes =
                    {
                        "openid",
                        "profile",
                        "email",
                        "role",
                        "jseg",
                        "jobid",
                        "regid",
                        "api1",
                        "api1scope",
                    },

                    RedirectUris = angularRedirectUris.Split(','),
                    PostLogoutRedirectUris = angularPostLogoutRedirectUris.Split(',')
                },
                new Client
                {
                    ClientId = "mvcclient",
                    ClientName = "mvcclient",

                    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
                    ClientSecrets = { new Secret(mvcClientSecrets.Sha256()) },

                    RequireConsent = true,
                    AllowRememberConsent = false,

                    RedirectUris = mvcRedirectUris.Split(','),
                    FrontChannelLogoutUri = mvcFrontChannelLogoutUri,
                    PostLogoutRedirectUris = mvcPostLogoutRedirectUris.Split(','),

                    AllowOfflineAccess = true,
                    AllowedScopes = new List<string>
                    {
                        "openid",
                        "profile",
                        "api1"
                    }
                },

            };
        }

角度app.module.ts:

export class AppModule {
  constructor(
    private oidcSecurityService: OidcSecurityService
  ) {
    const openIDImplicitFlowConfiguration = new OpenIDImplicitFlowConfiguration();

    openIDImplicitFlowConfiguration.storage = sessionStorage;
    openIDImplicitFlowConfiguration.stsServer = environment.oidc.stsServer;
    openIDImplicitFlowConfiguration.redirect_url = environment.oidc.redirect_url;
    // The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer
    // identified by the iss (issuer) Claim as an audience.
    // The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience,
    // or if it contains additional audiences not trusted by the Client.
    openIDImplicitFlowConfiguration.client_id = 'angularclient';
    openIDImplicitFlowConfiguration.response_type = 'id_token token';
    openIDImplicitFlowConfiguration.scope = 'openid profile email api1scope';
    openIDImplicitFlowConfiguration.post_logout_redirect_uri = environment.oidc.post_logout_redirect_uri;
    // openIDImplicitFlowConfiguration.start_checksession = this.oidcConfigService.clientConfiguration.start_checksession;

    openIDImplicitFlowConfiguration.silent_renew = true;
    openIDImplicitFlowConfiguration.silent_renew_url = environment.oidc.silent_renew_url;

    openIDImplicitFlowConfiguration.post_login_route = environment.oidc.post_login_route;
    // HTTP 403
    openIDImplicitFlowConfiguration.forbidden_route = '/forbidden';
    // HTTP 401
    openIDImplicitFlowConfiguration.unauthorized_route = '/unauthorized';
    openIDImplicitFlowConfiguration.log_console_warning_active = environment.oidc.log_console_warning_active;
    openIDImplicitFlowConfiguration.log_console_debug_active = environment.oidc.log_console_debug_active;
    // id_token C8: The iat Claim can be used to reject tokens that were issued too far away from the current time,
    // limiting the amount of time that nonces need to be stored to prevent attacks.The acceptable range is Client specific.
    openIDImplicitFlowConfiguration.max_id_token_iat_offset_allowed_in_seconds = environment.oidc.max_id_token_iat_offset_allowed_in_seconds;

    // openIDImplicitFlowConfiguration.iss_validation_off = false;
    // configuration.FileServer = this.oidcConfigService.clientConfiguration.apiFileServer;
    // configuration.Server = this.oidcConfigService.clientConfiguration.apiServer;

    const authWellKnownEndpoints = new AuthWellKnownEndpoints();
    authWellKnownEndpoints.issuer = environment.oidc.stsServer;
    authWellKnownEndpoints.jwks_uri = `${environment.oidc.stsServer}/.well-known/openid-configuration/jwks`;
    authWellKnownEndpoints.authorization_endpoint = `${environment.oidc.stsServer}/connect/authorize`;
    authWellKnownEndpoints.token_endpoint = `${environment.oidc.stsServer}/connect/token`;
    authWellKnownEndpoints.userinfo_endpoint = `${environment.oidc.stsServer}/connect/userinfo`;
    authWellKnownEndpoints.end_session_endpoint = `${environment.oidc.stsServer}/connect/endsession`;
    authWellKnownEndpoints.check_session_iframe = `${environment.oidc.stsServer}/connect/checksession`;
    authWellKnownEndpoints.revocation_endpoint = `${environment.oidc.stsServer}/connect/revocation`;
    authWellKnownEndpoints.introspection_endpoint = `${environment.oidc.stsServer}/connect/introspect`;

    this.oidcSecurityService.setupModule(
      openIDImplicitFlowConfiguration,
      authWellKnownEndpoints
    );

  }
}

Asp.Net核心2.2 api项目start.cs:

services.AddAuthentication("Bearer")
                .AddIdentityServerAuthentication(options =>
                {
                    options.Authority = Configuration.GetValue<string>("IdentityServer4Strings:Authority");
                    options.RequireHttpsMetadata = Configuration.GetValue<bool>("IdentityServer4Strings:RequireHttpsMetadata");
                    options.ApiName = Configuration.GetValue<string>("IdentityServer4Strings:ApiName");

                    options.SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Jwt;
                    options.ApiSecret = Configuration.GetValue<string>("IdentityServer4Strings:STSTSICApisSecuredSecret");
                    options.EnableCaching = true;
                    options.CacheDuration = TimeSpan.FromMinutes(10); // that's the default
                });


Asp.Net core 2.2 sts project start.cs:

        services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

        var identityServer = services.AddIdentityServer(options =>
        {
            options.Events.RaiseErrorEvents = true;
            options.Events.RaiseInformationEvents = true;
            options.Events.RaiseFailureEvents = true;
            options.Events.RaiseSuccessEvents = true;
        })
            .AddProfileService<IdentityWithAdditionalClaimsProfileService>()
            //.AddTestUsers(TestUsers.Users)
            // this adds the config data from DB (clients, resources, CORS)
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString);
            })
            // this adds the operational data from DB (codes, tokens, consents)
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString);

                // this enables automatic token cleanup. this is optional.
                options.EnableTokenCleanup = true;
            })
            .AddProfileService<IdentityWithAdditionalClaimsProfileService>()
            .AddAspNetIdentity<ApplicationUser>();


        services.AddTransient<IProfileService, IdentityWithAdditionalClaimsProfileService>();



Api authorize protection decorator (have tried both):
`
        //[Authorize]
        [Authorize(AuthenticationSchemes = "Bearer")]
`

Asp.Net core 2.2 sts start.cs:
`
            services.AddIdentity<ApplicationUser, IdentityRole>()
                    .AddEntityFrameworkStores<ApplicationDbContext>()
                    .AddDefaultTokenProviders();

            var identityServer = services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
            })
                .AddProfileService<IdentityWithAdditionalClaimsProfileService>()
                //.AddTestUsers(TestUsers.Users)
                // this adds the config data from DB (clients, resources, CORS)
                .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString);
                })
                // this adds the operational data from DB (codes, tokens, consents)
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString);

                    // this enables automatic token cleanup. this is optional.
                    options.EnableTokenCleanup = true;
                })
                .AddProfileService<IdentityWithAdditionalClaimsProfileService>()
                .AddAspNetIdentity<ApplicationUser>();


            services.AddTransient<IProfileService, IdentityWithAdditionalClaimsProfileService>();

Asp.Net核心2.2 sts项目IdentityWithAdditionalClaims处理程序:

public IdentityWithAdditionalClaimsProfileService(UserManager<ApplicationUser> userManager, IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, SqlDbContext Sql)
        {
            _userManager = userManager;
            _claimsFactory = claimsFactory;
            _context = Sql;
        }

        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);
            var principal = await _claimsFactory.CreateAsync(user);

            var claims = principal.Claims.ToList();
            var tsicCustomClaims = await GetTSICCustomClaims(claims);

            claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();
            claims.Add(new Claim(JwtClaimTypes.Scope, "api1"));

            claims.Add(new Claim("regid", tsicCustomClaims.RegId.ToString()));
            claims.Add(new Claim("jseg", tsicCustomClaims.JobPath));
            claims.Add(new Claim("jobid", tsicCustomClaims.JobId.ToString()));
            claims.Add(new Claim(JwtClaimTypes.Role, tsicCustomClaims.RoleName));

            claims.Add(new Claim(JwtClaimTypes.GivenName, tsicCustomClaims.FirstName));
            claims.Add(new Claim(JwtClaimTypes.FamilyName, tsicCustomClaims.LastName));

            claims.Add(new Claim(IdentityServerConstants.StandardScopes.Email, tsicCustomClaims.EMail));

            context.IssuedClaims = claims;

        }

错误:

When accessing the protected api I get from Asp.Net core 2.2 api project:

    [09:29:03 Information] Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler
    Failed to validate the token.
    Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed. Audiences: 'https://localhost:44340/resources'. Did not match: validationParameters.ValidAudience: 'api1' or validationParameters.ValidAudiences: 'null'.
       at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
       at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateAudience(IEnumerable`1 audiences, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
       at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
       at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
       at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()

    [09:29:03 Information] Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler
    BearerIdentityServerAuthenticationJwt was not authenticated. Failure message: IDX10214: Audience validation failed. Audiences: 'https://localhost:44340/resources'. Did not match: validationParameters.ValidAudience: 'api1' or validationParameters.ValidAudiences: 'null'.

    [09:29:03 Information] IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler
    Bearer was not authenticated. Failure message: IDX10214: Audience validation failed. Audiences: 'https://localhost:44340/resources'. Did not match: validationParameters.ValidAudience: 'api1' or validationParameters.ValidAudiences: 'null'.

启动Asp.Net Core 2.2 sts项目时,我得到:

Seeding database...
Clients already populated
IdentityResources already populated
ApiResources already populated
Done seeding database.

[09:28:09 Information] IdentityServer4.Startup
Starting IdentityServer4 version 2.3.2.0

[09:28:09 Information] IdentityServer4.Startup
Using the default authentication scheme Identity.Application for IdentityServer

[09:28:09 Debug] IdentityServer4.Startup
Using Identity.Application as default ASP.NET Core scheme for authentication

[09:28:09 Debug] IdentityServer4.Startup
Using Identity.External as default ASP.NET Core scheme for sign-in

[09:28:09 Debug] IdentityServer4.Startup
Using Identity.External as default ASP.NET Core scheme for sign-out

[09:28:09 Debug] IdentityServer4.Startup
Using Identity.Application as default ASP.NET Core scheme for challenge

[09:28:09 Debug] IdentityServer4.Startup
Using Identity.Application as default ASP.NET Core scheme for forbid

[09:28:10 Debug] IdentityServer4.EntityFramework.TokenCleanup
Starting grant removal

Hosting environment: Development
Content root path: E:\Projects-STS\TSIC\TSIC.STS
Now listening on: https://localhost:44340
Application started. Press Ctrl+C to shut down.
[09:28:13 Debug] IdentityServer4.Startup
Login Url: /Account/Login

[09:28:13 Debug] IdentityServer4.Startup
Login Return Url Parameter: ReturnUrl

[09:28:13 Debug] IdentityServer4.Startup
Logout Url: /Account/Logout

[09:28:13 Debug] IdentityServer4.Startup
ConsentUrl Url: /consent

[09:28:13 Debug] IdentityServer4.Startup
Consent Return Url Parameter: returnUrl

[09:28:13 Debug] IdentityServer4.Startup
Error Url: /home/error

[09:28:13 Debug] IdentityServer4.Startup
Error Id Parameter: errorId

[09:28:25 Debug] IdentityServer4.Hosting.EndpointRouter
Request path /connect/authorize matched to endpoint type Authorize

[09:28:25 Debug] IdentityServer4.Hosting.EndpointRouter
Endpoint enabled: Authorize, successfully created handler: IdentityServer4.Endpoints.AuthorizeEndpoint

[09:28:25 Information] IdentityServer4.Hosting.IdentityServerMiddleware
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize

[09:28:25 Debug] IdentityServer4.Endpoints.AuthorizeEndpoint
Start authorize request

[09:28:25 Debug] IdentityServer4.Endpoints.AuthorizeEndpoint
No user present in authorize request

[09:28:25 Debug] IdentityServer4.Validation.AuthorizeRequestValidator
Start authorize request protocol validation

[09:28:26 Debug] IdentityServer4.EntityFramework.Stores.ClientStore
angularclient found in database: True

[09:28:26 Debug] IdentityServer4.Stores.ValidatingClientStore
client configuration validation for client angularclient succeeded.

[09:28:27 Debug] IdentityServer4.EntityFramework.Stores.ResourceStore
Found ["openid", "profile", "email", "api1scope"] identity scopes in database

[09:28:27 Debug] IdentityServer4.EntityFramework.Stores.ResourceStore
Found [] API scopes in database

[09:28:27 Debug] IdentityServer4.EntityFramework.Stores.ResourceStore
Found ["openid", "profile", "email", "api1scope"] identity scopes in database

[09:28:27 Debug] IdentityServer4.EntityFramework.Stores.ResourceStore
Found [] API scopes in database

我想我靠近这里,只需要朝正确的方向推动即可。

我目前专注于这一行:

[09:28:27 Debug] IdentityServer4.EntityFramework.Stores.ResourceStore
Found [] API scopes in database

认为这与api项目错误有关:

IDX10214: Audience validation failed. Audiences: 'https://localhost:44340/resources'. Did not match: validationParameters.ValidAudience: 'api1' or validationParameters.ValidAudiences: 'null'.

这让我很烦,因为数据库确实在SQL Server的dbo.ApiScopes中有一个条目:

Id  Name    DisplayName Description Required    Emphasize   ShowInDiscoveryDocument ApiResourceId
9   api1    Scope for the api1 ApiResource  NULL    0   0   1   12

我很感谢您的帮助

2 个答案:

答案 0 :(得分:0)

在角度配置中,您可以:

 openIDImplicitFlowConfiguration.scope = 'openid profile email api1scope';

但是,它应该与api1的有效范围之一匹配:

 openIDImplicitFlowConfiguration.scope = 'openid profile email api1';

Identity Server 4仅在您请求属于给定api的至少一个范围并且您的客户端被允许使用该范围时,才将Api资源添加为有效的令牌访问者。

答案 1 :(得分:0)

Vidmantas,感谢您的回复,我尝试了该操作,并且发生了相同的错误。然后,我很幸运并解决了(id令牌与访问令牌中指示的不同受众存在问题,以及如何通过Api项目startup.cs中的IdentityServer4配置设置id令牌aud:):

知道了,希望对其他人有帮助

登录后返回的角度客户端:

id令牌:

{
  "nbf": 1550240640,
  "exp": 1550273640,
  "iss": "https://localhost:44340",
  "aud": "https://localhost:44340/resources",
  "client_id": "angularclient",
  "sub": "71765055-647D-432E-AFB6-0F84218D0247",
  "auth_time": 1550240638,
  "idp": "local",
  "regid": "xxxx",
  "jseg": "xxxxx",
  "jobid": "b0984a87-172a-436e-a382-e95de3e1059f",
  "role": "xxxx",
  "given_name": "xxxxx",
  "family_name": "xxxx",
  "email": "xxxx",
  "scope": [
    "openid",
    "profile",
    "email"
  ],
  "amr": [
    "pwd"
  ]
}

和访问令牌:

{
  "nbf": 1550240640,
  "exp": 1550243640,
  "iss": "https://localhost:44340",
  "aud": "angularclient",
  "nonce": "N0.55036966062308791550240634889",
  "iat": 1550240640,
  "at_hash": "yNVxDVHkmEmUvurl7XlzuA",
  "sid": "f54dee03793e7cc202b57f1d6de7622e",
  "sub": "71765055-647D-432E-AFB6-0F84218D0247",
  "auth_time": 1550240638,
  "idp": "local",
  "preferred_username": "TSICSuperUser",
  "name": "xxxx",
  "email": "xxxxx",
  "email_verified": true,
  "regid": "xxxxx",
  "jseg": "xxxxx",
  "jobid": "xxxxxxf",
  "role": "xxxxx",
  "given_name": "xxxx",
  "family_name": "xxxxx",
  "amr": [
    "pwd"
  ]
}

注意不同的受众群体(aud:)

Asp.Net Core 2.2 Api项目startup.cs配置了IdentityServer4:

                .AddIdentityServerAuthentication(options =>
                {
                    options.Authority = Configuration.GetValue<string>("IdentityServer4Strings:Authority");
                    options.RequireHttpsMetadata = Configuration.GetValue<bool>("IdentityServer4Strings:RequireHttpsMetadata");
                    options.ApiName = "api1";

                    options.SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Jwt;
                    options.ApiSecret = Configuration.GetValue<string>("IdentityServer4Strings:STSTSICApisSecuredSecret");
                    options.EnableCaching = true;
                    options.CacheDuration = TimeSpan.FromMinutes(10); // that's the default
                });

而Bearer身份验证错误为:

2019-02-14 18:03:15.188 -07:00 [DBG] AuthenticationScheme: Bearer was not authenticated.
2019-02-14 18:04:04.360 -07:00 [INF] Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed. Audiences: 'https://localhost:44340/resources'. Did not match: validationParameters.ValidAudience: 'api1' or validationParameters.ValidAudiences: 'null'.
   at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateAudience(IEnumerable`1 audiences, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
2019-02-14 18:04:04.430 -07:00 [INF] BearerIdentityServerAuthenticationJwt was not authenticated. Failure message: IDX10214: Audience validation failed. Audiences: 'https://localhost:44340/resources'. Did not match: validationParameters.ValidAudience: 'api1' or validationParameters.ValidAudiences: 'null'.
2019-02-14 18:04:04.433 -07:00 [INF] Bearer was not authenticated. Failure message: IDX10214: Audience validation failed. Audiences: 'https://localhost:44340/resources'. Did not match: validationParameters.ValidAudience: 'api1' or validationParameters.ValidAudiences: 'null'.

错误的“ api1”: Did not match: validationParameters.ValidAudience: 'api1'

引用startup.cs

.AddIdentityServerAuthentication
options.ApiName = "api1";

将Asp.Net Core 2.2 Api项目startup.cs更改为:

            // critical for bearer authentication, the audience of the id token (set by Options.ApiName) is equal to this value
            var idTokenAudience = $"{Configuration.GetValue<string>("IdentityServer4Strings:Authority")}/resources";

            services.AddAuthentication("Bearer")
                .AddIdentityServerAuthentication(options =>
                {
                    options.Authority = Configuration.GetValue<string>("IdentityServer4Strings:Authority");
                    options.RequireHttpsMetadata = Configuration.GetValue<bool>("IdentityServer4Strings:RequireHttpsMetadata");
                    options.ApiName = idTokenAudience;

                    options.SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Jwt;
                    options.ApiSecret = Configuration.GetValue<string>("IdentityServer4Strings:STSTSICApisSecuredSecret");
                    options.EnableCaching = true;
                    options.CacheDuration = TimeSpan.FromMinutes(10); // that's the default
                });

解决了这个问题。

2019-02-15 07:45:12.414 -07:00 [INF] Successfully validated the token.
2019-02-15 07:45:12.414 -07:00 [DBG] AuthenticationScheme: Bearer was successfully authenticated.