ASP.NET Core 2.0中IAuthorizationService与过期Bearer令牌问题咨询
我之前在ASP.NET Core 2.x项目里切换授权方式时也踩过一模一样的坑,脱离[Authorize]特性改用IAuthorizationService+DefaultAuthorizationPolicyProvider的场景,确实因为少了特性的自动配置兜底,容易忽略一些关键细节,尤其是2.0版本的授权体系和后续3.x+版本还有不少差异。下面是我当时排查和解决的几个核心方向:
1. 先确认授权服务与策略的注册是否正确
ASP.NET Core 2.0里DefaultAuthorizationPolicyProvider不会自动帮你关联Bearer认证方案,所以必须在Startup的ConfigureServices里手动把默认策略和Bearer绑定:
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; public void ConfigureServices(IServiceCollection services) { // 先注册Bearer认证(这个你之前正常运行的话应该已经有了) services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 你的令牌验证配置,比如Issuer、Audience、SigningKey等 }); // 关键:配置授权策略,必须关联Bearer认证方案 services.AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder() // 指定用Bearer认证来验证用户身份 .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser() // 加上你需要的其他授权要求,比如角色、声明: // .RequireRole("Admin") // .RequireClaim("Permission", "EditData") .Build(); }); // 注册授权服务和策略提供者(如果是用默认的,其实可以不用手动注册,但显式写出来更清晰) services.AddSingleton<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>(); services.AddScoped<IAuthorizationService, DefaultAuthorizationService>(); }
如果你的项目用了自定义策略,也要确保每个自定义策略都添加了AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme),不然授权服务不知道该用哪种认证方式去校验令牌。
2. 检查调用IAuthorizationService的姿势是否正确
很多人踩坑是因为调用时漏传了关键参数,或者用错了返回结果。比如在控制器里的正确调用方式:
private readonly IAuthorizationService _authorizationService; // 构造函数注入 public YourController(IAuthorizationService authorizationService) { _authorizationService = authorizationService; } public async Task<IActionResult> YourAction() { // 关键:必须传入当前HttpContext的User对象,这是Bearer令牌解析后的身份信息 // 如果用默认策略,第三个参数可以省略;如果用自定义策略,要传策略名称 var authResult = await _authorizationService.AuthorizeAsync(User, null, "YourCustomPolicy"); if (!authResult.Succeeded) { // 注意:授权失败要返回ForbidResult,而不是UnauthorizedResult! // Unauthorized是给认证失败用的(比如令牌无效),Forbid是认证通过但授权不通过 return Forbid(JwtBearerDefaults.AuthenticationScheme); } // 授权通过后的逻辑 return Ok(); }
这里要重点提醒:别把Forbid和Unauthorized搞混,很多人返回Unauthorized导致调试时误以为是令牌认证出问题,其实是授权没通过。
3. 确认中间件的注册顺序是否正确
在Startup的Configure方法里,认证中间件必须在授权中间件之前注册,不然授权服务拿到的User会是未认证的空对象:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // 其他中间件(比如ExceptionHandler、StaticFiles等) // 先加认证中间件 app.UseAuthentication(); // 再加授权中间件 app.UseAuthorization(); // 路由、端点等中间件 app.UseMvc(); }
这个顺序错了的话,前面所有的配置都白搭,因为授权时根本拿不到令牌解析后的用户信息。
4. 排查令牌声明与策略要求是否匹配
如果上面的配置都没问题,那就要检查令牌本身的内容了:
- 用JWT解析工具(比如本地的解析代码或者在线工具)打开你的Bearer令牌,查看
payload里的声明是否符合策略要求(比如角色、权限声明是否存在); - 在代码里临时打印
User.Claims,确认令牌的声明是否被正确解析到当前用户对象中:
// 在控制器里临时添加调试代码 var claims = User.Claims.Select(c => $"{c.Type}: {c.Value}").ToList(); // 输出到日志或者控制台
如果声明没被正确解析,那可能是Bearer认证的配置有问题(比如Issuer/Audience不匹配),这时候要回到认证配置里排查。
最后补充一句:ASP.NET Core 2.0的授权体系相对后续版本确实不够完善,很多细节需要手动把控,按照上面的步骤逐一排查,应该能解决你的问题。
内容的提问来源于stack exchange,提问作者Jammer

