为什么ASP.NET Core Identity 2.0授权filter导致我获得404?

我有一个控制器,我想只限制一个特定的角色,让我们说admin 。 在使用admin角色设置用户之后,我可以使用IsInRoleAsync方法(返回true)validation他是否在该角色上。 当使用[Authorize(Roles = "admin")]设置属性时,我得到的是同一个用户的404。 我正在使用持有者令牌(我不认为这是相关的,但无论如何),这就是我尝试调试的方法:

控制器没有[Authorize] :返回资源。 [好]

[Authorize]控制器: 当我使用Authentication: Bearer [access token] 时才返回资源Authentication: Bearer [access token] [确定]

[Authorize(Roles = "admin")]控制器:即使在拥有角色集的用户登录后,我也得到404 [NOK]

我不知道我是否缺少一些配置,但这是我的ConfigureServices:

 public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // Add framework services. services.AddDbContext(options => { options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")); options.UseOpenIddict(); }); services.AddIdentity() .AddEntityFrameworkStores() .AddDefaultTokenProviders(); services.AddOpenIddict(opt => { opt.AddEntityFrameworkCoreStores(); opt.AddMvcBinders(); opt.EnableTokenEndpoint("/api/token"); opt.AllowPasswordFlow(); opt.DisableHttpsRequirement(); //for dev only! opt.UseJsonWebTokens(); opt.AddEphemeralSigningKey(); opt.AllowRefreshTokenFlow(); opt.SetAccessTokenLifetime(TimeSpan.FromMinutes(5)); }); services.AddAuthentication(options => { options.DefaultScheme = OAuthValidationDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = OAuthValidationConstants.Schemes.Bearer; options.DefaultSignInScheme = IdentityConstants.ExternalScheme; }) .AddJwtBearer(options => { options.Authority = "http://localhost:44337/"; options.Audience = "resource_server"; options.RequireHttpsMetadata = false; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = OpenIdConnectConstants.Claims.Subject, RoleClaimType = OpenIdConnectConstants.Claims.Role }; }); services.Configure(options => { // Password settings options.Password.RequireDigit = true; options.Password.RequiredLength = 8; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = true; options.Password.RequireLowercase = false; // Lockout settings options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30); options.Lockout.MaxFailedAccessAttempts = 10; // User settings options.User.RequireUniqueEmail = true; // Add application services. options.ClaimsIdentity.UserNameClaimType= OpenIdConnectConstants.Claims.Name; options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject; options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role; }); services.AddSingleton(typeof(RoleManager)); // Add application services. services.AddTransient(); services.AddTransient(); 

您可能会收到404响应,因为身份 – 自动配置为服务的默认身份validation,登录/注销和质询/禁止方案services.AddIdentity() – 尝试将您重定向到“访问被拒绝页面”( Account/AccessDenied默认情况下为Account/AccessDenied ),这可能在您的应用程序中不存在。

尝试覆盖默认的挑战/禁止方案,看看它是否修复了您的问题:

 services.AddAuthentication(options => { // ... options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme; }); 

要解决第二个问题,请确保已禁用JWT声明映射function。 如果不是,JWT处理程序会将您的所有role声明“转换”为ClaimTypes.Role ,当您将其配置为使用role作为ClaimsPrincipal.IsInRole(...)使用的角色声明时, ClaimsPrincipal.IsInRole(...)RoleClaimType = OpenIdConnectConstants.Claims.Role )。

 services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { // ... options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Add(new JwtSecurityTokenHandler { // Disable the built-in JWT claims mapping feature. InboundClaimTypeMap = new Dictionary() }); }); 

我认为你需要的是检查索赔,而不是角色。 添加AuthorizeAttribute例如:

 [Authorize(Policy = "AdminOnly")] 

然后配置需要声明的策略:

 services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => policy.RequireClaim(OpenIdConnectConstants.Claims.Role, "Admin")); }); 

或者,出于调试目的或更高级的validation,您可以:

 services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => policy.RequireAssertion(ctx => { //do your checks return true; })); });