Некоторое время боролся с этим, не испытывая проблем с доступом к angular7-клиенту id4 проекта Asp.Net core 2.2 для входа в систему и получения jwt, боролся с доступом к angular7-клиенту asp.Net core 2.2 api project protected api, который находится подЗащита id4.
Декодирование jwt.io (значения x'd out):
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
);
}
}
Запускается проект API Asp.Net core 2.2 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 core 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'.
Это вызывает ошибки, потому что база данных имеетзапись в dbo.ApiScopes, из SQL Server:
Id Name DisplayName Description Required Emphasize ShowInDiscoveryDocument ApiResourceId
9 api1 Scope for the api1 ApiResource NULL 0 0 1 12
Я благодарен за любую помощь