使用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核心客户端
// 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();
在这里,我收到了一个承载令牌,但似乎不被接受(Identity Server发出以下错误(。它看起来如下:
{
"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核心Web API启动.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
。如何找出潜在的错误?
在stratup.cs配置方法中,请确保应用程序的顺序。使用是正确的。
例如app.UseMvc()
之前的app.UseAuthentication();