You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core自定义授权策略:RequireAuthenticatedUser与RequireClaim的区别

ASP.NET Core 自定义授权策略的差异及未认证用户持声明的场景分析

一、两个自定义授权策略的核心差异

咱们先把两段代码摆出来,直观对比:

策略1:仅要求声明存在

services.AddAuthorization(options => 
{ 
    options.AddPolicy("MyCustomPolicy", policyBuilder => 
        policyBuilder.RequireClaim("SomeClaim")); 
});

策略2:要求已认证 + 声明存在

services.AddAuthorization(options => 
{ 
    options.AddPolicy("MyCustomPolicy", policyBuilder => 
        policyBuilder.RequireAuthenticatedUser().RequireClaim("SomeClaim")); 
});

两者的关键区别在于是否强制要求用户已完成认证:

  • 策略1只校验当前HttpContext.User中是否包含"SomeClaim"声明,完全不关心用户是否处于认证状态——哪怕是匿名用户,只要有这个声明就能通过授权。
  • 策略2会先通过RequireAuthenticatedUser()校验用户是否已认证(即User.Identity.IsAuthenticated == true),只有通过这一步,才会继续检查是否存在"SomeClaim"声明。

从底层逻辑来看:

  • RequireClaim本质是添加了ClaimsAuthorizationRequirement,这个需求只扫描用户的声明集合,不涉及认证状态校验。
  • RequireAuthenticatedUser则是添加了DenyAnonymousAuthorizationRequirement,它会直接判断用户身份的IsAuthenticated属性,未认证用户会直接被拦截。

二、未认证用户拥有声明的情况是否存在?

答案是完全存在!

在ASP.NET Core中,ClaimsPrincipal(也就是HttpContext.User)并不只属于已认证用户。哪怕用户是匿名状态(IsAuthenticated = false),我们依然可以为其创建ClaimsPrincipal并添加声明。

工作机制

ASP.NET Core的身份系统基于ClaimsPrincipal和ClaimsIdentity:

  1. 对于未认证用户,默认的ClaimsPrincipal会包含一个ClaimsIdentity,但这个Identity的IsAuthenticated属性为false,且通常没有额外声明。
  2. 我们可以通过中间件、自定义身份构造逻辑等方式,为这个未认证的ClaimsPrincipal添加任意声明。这些声明会被后续的授权逻辑(比如策略1)识别并使用。

演示示例

下面是一个简单的示例,展示如何给未认证用户添加声明,并验证策略1的授权行为:

1. 注册授权策略(使用策略1)

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("MyCustomPolicy", policy => policy.RequireClaim("SomeClaim"));
});

var app = builder.Build();

// 添加自定义中间件,给未认证用户添加声明
app.Use(async (context, next) =>
{
    // 如果用户未认证
    if (!context.User.Identity.IsAuthenticated)
    {
        // 创建一个未认证的ClaimsIdentity,并添加声明
        var identity = new ClaimsIdentity(null, /* 认证类型为空,代表未认证 */);
        identity.AddClaim(new Claim("SomeClaim", "AnonymousUserValue"));
        
        // 替换当前的User为包含这个Identity的ClaimsPrincipal
        context.User = new ClaimsPrincipal(identity);
    }
    await next();
});

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

2. 控制器中使用授权策略

// HomeController.cs
public class HomeController : Controller
{
    [Authorize(Policy = "MyCustomPolicy")]
    public IActionResult PolicyProtected()
    {
        // 获取声明值
        var claimValue = User.FindFirstValue("SomeClaim");
        return Content($"通过授权!当前用户声明值:{claimValue}");
    }

    public IActionResult Index()
    {
        return Content("首页,无需授权");
    }
}

3. 测试效果

直接访问/Home/PolicyProtected,你会发现:

  • 用户是未认证状态(User.Identity.IsAuthenticated为false),但因为我们添加了SomeClaim声明,所以成功通过了MyCustomPolicy的授权,返回对应的内容。
  • 如果换成策略2,这个请求会被拦截,因为未满足RequireAuthenticatedUser()的要求。

内容的提问来源于stack exchange,提问作者SpiritBob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 15:18:01