Проблемы с сервером идентификации. AuthenticationScheme: носителю был запрошен токен, полученный с помощью учетных данных клиента. Как узнать причину ошибки?
У меня возникают проблемы с аутентификацией некоторых запросов интеграционных тестов при работе с Identity Server 4 (ASP.NET Core 3.1).
Моя установка выглядит следующим образом:
Конфигурация сервера идентификации
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Email(),
new IdentityResources.Profile(),
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("resourceapi", "Resource API")
{
Scopes = {new Scope("api.read")}
}
};
}
public static IEnumerable<Client> GetClients()
{
return new[]
{
new Client
{
RequireConsent = false,
ClientId = "MY_CLIENT_ID",
ClientName = "My Client Name",
// code is required for SPA, client credentials for test runner
AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,
AllowedScopes = {"openid", "profile", "email", "api.read"},
RedirectUris = {"http://localhost:4201/auth-callback"},
PostLogoutRedirectUris = {"http://localhost:4201/"},
AllowedCorsOrigins = {"http://localhost:4201"},
AllowAccessTokensViaBrowser = true,
AccessTokenLifetime = 3600,
RequireClientSecret = false
}
};
}
services.AddIdentity<AppUser, IdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder => builder.UseSqlServer(Configuration.GetConnectionString("Default"));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30; // interval in seconds
})
//.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<AppUser>();
Клиент ASP.NET Core
// this is called from Startup.ConfigureServices
public static void ConfigureSecurity(this IServiceCollection services, IConfiguration configuration)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.Authority = configuration.GetSection("Idam").GetValue<string>("BaseUrl"); // http://localhost:54916
o.Audience = configuration.GetSection("Idam").GetValue<string>("Audience"); // "resourceapi"
o.RequireHttpsMetadata = false;
});
services.AddAuthorization();
}
Код интеграционных тестов
var client = new HttpClient();
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
Address = $"{IdentityServerUrl}/connect/token",
ClientId = "MY_CLIENT_ID",
ClientSecret = IdentityServerPass,
Scope = "api.read"
}).ConfigureAwait(false);
tokenResponse.HttpResponse.EnsureSuccessStatusCode();
Здесь я получаю токен на предъявителя, но, похоже, он не принимается (сервер идентификации выдает ошибку, указанную ниже). Выглядит это примерно так:
{
"nbf": 1587392198,
"exp": 1587395798,
"iss": "http://localhost:54916",
"aud": "resourceapi",
"client_id": "STACKOVERFLOW_METRO_MIRROR",
"scope": [
"api.read"
]
}
> IdentityServer4.Hosting.IdentityServerMiddleware: Information:
> Invoking IdentityServer endpoint:
> IdentityServer4.Endpoints.TokenEndpoint for /connect/token
> IdentityServer4.Validation.TokenRequestValidator: Information: Token
> request validation success, { "ClientId":
> "STACKOVERFLOW_METRO_MIRROR", "ClientName": "My Client Name",
> "GrantType": "client_credentials", "Scopes": "api.read", "Raw": {
> "grant_type": "client_credentials",
> "scope": "api.read",
> "client_id": "MY_CLIENT_ID",
> "client_secret": "***REDACTED***" } } Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request
> starting HTTP/1.1 GET
> http://localhost:44324/api/GeneralData/GetAllTags
> Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware:
> Information: No cached response available for this request.
> Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:
> Information: Authorization failed.
> Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:
> Information: AuthenticationScheme: Bearer was challenged.
Поскольку моя установка также включает SPA, который может успешно аутентифицироваться (вход через форму входа в Identity Server -> получить токен -> API успешно использует токен), я расшифровал такой токен, чтобы увидеть, вижу ли я какую-либо соответствующую разницу, которая может показать, что Мне не хватает тестовой проверки подлинности:
{
"nbf": 1587393059,
"exp": 1587396659,
"iss": "http://localhost:54916",
"aud": "resourceapi",
"client_id": "MY_CLIENT_ID",
"sub": "fd351b3b-dfb2-4f2f-8987-af9d23c9dc6e",
"auth_time": 1587393055,
"idp": "local",
"given_name": "test",
"email": "test@example.com",
"scope": [
"openid",
"email",
"profile",
"api.read"
],
"amr": [
"pwd"
]
}
ASP.NET Core Web API Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.ConfigureCustomServices();
services.ConfigureSettings(Configuration);
services.ConfigureSecurity(Configuration);
services.ConfigureMvc();
services.BindLogging();
services.ConfigureRedisCache(Configuration);
services.ConfigureApiExplorer();
services.AddHttpContextAccessor();
services.AddDbContext(Configuration);
ConfigureAuditNet();
services.AddCorsAndPolicy();
services.ConfigureHangfire(Configuration);
services.AddSignalR();
services.AddAutoMapper(typeof(QuestionProfile).Assembly);
services.AddHealthChecks();
services
.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
ILoggingService logger, IHostApplicationLifetime lifetime, IServiceProvider serviceProvider,
ISoApiDailyRequestInfoService soApiDailyRequestInfoService)
{
app.UseResponseCaching();
app.UseMiddleware<ResponseTimeMiddleware>();
app.ProtectHangfireDashboard();
app.ConfigureExceptionPage(env);
app.StartHangFireJobs(serviceProvider, Configuration);
ConfigureApplicationLifetime(logger, lifetime, soApiDailyRequestInfoService);
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.EnsureAppUserMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<PostHub>("/post");
endpoints.MapHealthChecks("/health");
});
app.ConfigureAuditMiddleware();
app.UseSwagger();
}
К сожалению, сервер Identity выдает очень общую ошибку, и я действительно вижу, чего здесь не хватает.
Вопрос: проблемы с сервером идентификацииAuthenticationScheme: Bearer was challenged
для токена, полученного с помощью учетных данных клиента. Как узнать причину ошибки?
1 ответ
В методе конфигурации stratup.cs убедитесь, что последовательность app.Use... верна.
Например app.UseAuthentication();
перед app.UseMvc()