最常见原因是app.UseAuthentication()未在app.UseAuthorization()之前调用,导致User.Identity.IsAuthenticated恒为false,所有[Authorize(Policy="xxx")]直接返回401;必须确保中间件顺序为UseRouting→UseAuthentication→UseAuthorization→MapControllers。

Policy 为什么注册了却完全不生效
最常见原因是 app.UseAuthentication() 没在 app.UseAuthorization() 之前调用,或者根本没调用 —— 这会导致 HttpContext.User.Identity.IsAuthenticated 始终为 false,所有 [Authorize(Policy = "xxx")] 都直接返回 401,连策略逻辑都不会进。
必须保证中间件顺序是:app.UseRouting() → app.UseAuthentication() → app.UseAuthorization() → app.MapControllers()(.NET 6+ Minimal Hosting 模型下尤其容易把 UseAuthentication() 写在 MapControllers() 后面)。
- 仅在
Program.cs中调用builder.Services.AddAuthentication()不等于启用了认证中间件 - 若使用
MapControllers(),必须显式调用app.UseAuthorization();用UseEndpoints()则需确保endpoints.EnableEndpointRouting = true - 调试时直接打印
User.Identity.IsAuthenticated和User.Claims.ToList(),比猜更可靠
RequireClaim("role", "Admin") 为什么总失败
因为 RequireClaim 是严格字符串匹配:声明类型名(type)和值(value)都必须完全一致,且大小写敏感。你登录时写的是 new Claim("role", "Admin"),但默认 RequireRole("Admin") 查的是 ClaimTypes.Role(即 "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"),两者 type 不同,永远不匹配。
- 要么统一用
ClaimTypes.Role构造声明:new Claim(ClaimTypes.Role, "Admin") - 要么在认证配置中显式指定角色声明类型:
options.RoleClaimType = "role"(Cookie)或options.TokenValidationParameters.RoleClaimType = "role"(JWT) -
RequireClaim("Permission", "edit")要求用户 Claims 中存在类型为"Permission"、值为"edit"的声明,不能是"permission"或"EDIT"
自定义 AuthorizationHandler 总是被跳过
Handler 不执行,90% 是策略名没对上,或 Handler 没注册进 DI 容器。策略注册、特性绑定、依赖注入三者必须严丝合缝。
- 策略名必须和
AddPolicy("CanEditOrder", ...)中第一个参数完全一致,包括大小写 - Handler 类型必须通过
builder.Services.AddSingleton<IAuthorizationHandler, CanEditOrderHandler>()注册(不是AddTransient或AddScoped) - Handler 中别用
throw,要用context.Fail()或context.Succeed(requirement),否则会中断整个 pipeline - 如果 Handler 里要查数据库,记得注入
IDbContextFactory<AppDbContext>,避免 DbContext 生命周期冲突
跨平台部署时 Policy 行为不一致
Policy 本身是纯 .NET 逻辑,不直接受操作系统影响 —— 但它的输入(Claims)和运行环境(如文件权限、token 解析)可能因平台而异。比如 Linux 容器里 JWT 时间戳校验失败,或 macOS 沙盒限制了密钥读取,都会导致认证失败,进而让 Policy 根本没机会运行。
- 不要在 Handler 里硬编码路径(如
"C:\config.json"),用Path.Combine(Environment.GetFolderPath(...), "config.json") - 检查 token 是否含必要 claim:Linux/macOS 上某些 JWT 库对时间精度、签名算法支持略有差异
- 若 Policy 依赖本地资源(如配置文件、证书),先用
CanWriteToDirectory()类方法验证访问权限,再执行核心逻辑 - 调试时优先确认
User.Identity.IsAuthenticated在各平台是否都为true,这是 Policy 生效的前提


















