我正在使用Identity Server 4进行身份验证并通过efCore生成JWT,我有一个API和一个应该检索数据列表的get请求,因此当我使用邮递员“登录”时,如果我生成了令牌,再次登录并使用第一个令牌,尽管我对该特定操作具有AllowAnonymous,但get请求返回401和数据列表,有人知道这种行为的原因吗
获取端点
[HttpGet]
[AllowAnonymous]
public override Task<ActionResult<List<DataVM>>> Get()
{
return base.Get();
}
CRUD骨架
[HttpGet]
public virtual async Task<ActionResult<List<TValueModel>>> Get()
{
var userClaim = User.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject);
List<TValueModel> records;
if (userClaim != null)
{
records = await Mediator.Send(new GetAll<TModel, TValueModel>
{
UserId = Guid.Parse(userClaim.Value)
});
return records;
}
records = await Mediator.Send(new GetAll<TModel, TValueModel>());
return records;
}
启动
services.AddIdentity<User, Role>(options =>
{
options.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<SecurityStampValidatorOptions>(options => options.ValidationInterval = TimeSpan.FromSeconds(10));
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
})
.AddInMemoryIdentityResources(IdentityConfig.Ids)
.AddInMemoryApiResources(IdentityConfig.Apis)
.AddInMemoryClients(IdentityConfig.Clients)
.AddAspNetIdentity<User>();
builder.AddDeveloperSigningCredential();
services.AddTransient<IProfileService, ProfileService>();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultForbidScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
})
.AddIdentityServerAuthentication(options =>
{
options.Authority = Configuration.GetValue<string>("Host");
options.RequireHttpsMetadata = false;
options.JwtBearerEvents.OnAuthenticationFailed =
C =>
{
C.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
};
options.ApiName = "api1";
});
我认为这里发生的事情是AuthorizationMiddleware(added to the pipeline in your 'UseAuthorization' call)甚至在未命中控制器之前就将响应的状态代码设置为401。
[如果您使用MVC进行路由,则将通过从路由中检索的AuthorizationFilter执行授权。如果您使用的是端点路由,由于您提到这是一个api,因此AuthorizationMiddleware处理的可能性更大路由的授权(通过UseAuthorization调用添加到管道中)。
AuthorizeFilter和AuthorizationMiddleware都具有用于授权的镜像逻辑,无论最终使用哪种逻辑,其行为极有可能是相同的。
假设您在控制器上设置了Authorize属性或配置了其他一些授权数据,那么授权逻辑中的问题区域就是执行身份验证的AuthorizationMiddleware中的一部分。发生before the AllowAnonymous attribute is even searched for on the route。即使路由用AllowAnonymous属性标记,这也会导致应用任何与身份验证相关的失败。
由于已为身份验证方案配置了以下内容:
options.JwtBearerEvents.OnAuthenticationFailed =
C =>
{
C.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
};
当JwtBearer身份验证方案尝试基于令牌对用户进行身份验证时,似乎身份验证失败,并导致根据上面配置的OnAuthenticationFailed事件将状态代码设置为401。但是,此身份验证失败不会使请求失败,并且Web应用程序仍然能够执行端点操作,从而导致返回列表和未授权状态代码。
关于令牌为什么未通过身份验证的另一个问题,这需要进一步调查您的IdentityServer配置以及配置中使用的值。
这里还通过其他上下文讨论了使用AllowAnonymous对路由上的请求进行身份验证的ASP.NET Core的这种行为:https://github.com/aspnet/Security/issues/1577