User.HasClaim 未成功读取 .NET Core 2.0 Web Api 中的声明属性

stu*_*ilo 5 c# authorization azure-ad-b2c asp.net-core-2.0

将 Authorize 属性与我在 Startup.cs 中定义的策略一起使用时遇到问题。我编辑了我的控制器以手动检查声明。我可以看到包含具有正确范围的范围声明的声明,但是当我手动检查该声明/范围时,它返回为 false。我使用 Azure AD B2C 作为我的身份服务器并成功获得了一个经过验证的令牌。

这是我的 Startup.cs 中的代码:

    services.AddAuthorization(options =>
    {
        var policyRead = new AuthorizationPolicyBuilder()
            .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
            .RequireAuthenticatedUser()
            .RequireClaim("http://schemas.microsoft.com/identity/claims/scope", "vendor.read")
            .Build();
        options.AddPolicy("VendorRead", policyRead);

        var policyWrite = new AuthorizationPolicyBuilder()
            .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
            .RequireAuthenticatedUser()
            .RequireClaim("http://schemas.microsoft.com/identity/claims/scope", "vendor.write")
            .Build();
        options.AddPolicy("VendorWrite", policyWrite);
    });

    services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    }) 
        .AddJwtBearer(jwtOptions =>
        {
            jwtOptions.Authority = $"{Configuration["AzureAdB2C:Instance"]}/{Configuration["AzureAdB2C:TenantId"]}/{Configuration["AzureAdB2C:SignUpSignInPolicyId"]}/v2.0/";
            jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"];
            jwtOptions.RequireHttpsMetadata = true;
            jwtOptions.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = $"{Configuration["AzureAdB2C:Instance"]}/{Configuration["AzureAdB2C:TenantId"]}/v2.0/",
                ValidAudience = Configuration["AzureAdB2C:ClientId"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["AzureAdB2C:ClientSecret"]))
            };
            jwtOptions.Events = new JwtBearerEvents
            {
                OnAuthenticationFailed = AuthenticationFailed,
                OnTokenValidated = TokenValidated
            };
        });
Run Code Online (Sandbox Code Playgroud)

这是我手动检查声明的控制器代码:

// GET: api/Vendor/5
[HttpGet("{id}")]
public async Task<IActionResult> Get(VendorRequest request)
{
    var hasClaim1 = User.HasClaim(c => c.Type == "vendor.read");
    var hasClaim2 = User.HasClaim(c => c.Type == "scope");
    var hasClaim3 = User.HasClaim(c => c.Type == "scp");
    var hasClaim4 = User.HasClaim(c => c.Type == "http://schemas.microsoft.com/identity/claims/scope");
    var hasClaim5 = User.HasClaim("http://schemas.microsoft.com/identity/claims/scope", "vendor.read");
    var hasClaim7= User.HasClaim("http://schemas.microsoft.com/identity/claims/scope", "vendor.write");
    var allowed = await _authorization.AuthorizeAsync(User, "VendorRead");
    if (!allowed.Succeeded)
    {
        return StatusCode(StatusCodes.Status403Forbidden);
    }
Run Code Online (Sandbox Code Playgroud)

唯一返回为 true 的 hasClaim 是 hasClaim4。

以下是我的主张: 在此处输入图片说明

关于我做错了什么的任何想法?我只是想让 vendor.read 范围现在可以工作。

spo*_*ahn 6

范围声明是一个以空格分隔的列表,因此RequireClaim()在这种情况下助手将不起作用,但更通用RequireAssertion()

范围声明示例

"scp": "demo.read demo.write user_impersonation Test-Value"
Run Code Online (Sandbox Code Playgroud)

样本 RequireAssertion()

"scp": "demo.read demo.write user_impersonation Test-Value"
Run Code Online (Sandbox Code Playgroud)

样本 Controller

[Authorize("ScopeCheck")]
public class SecureController : Controller
{
    [HttpGet]
    public IActionResult Test()
    {
        return Ok(new { Message = "You are allowed" });
    }
}
Run Code Online (Sandbox Code Playgroud)

完整示例项目-示例令牌


访问令牌范围(RFC 6749 第 3.3 节)

scope 参数的值表示为以空格分隔、区分大小写的字符串列表。字符串由授权服务器定义。如果该值包含多个以空格分隔的字符串,则它们的顺序无关紧要,每个字符串都会为请求的范围添加一个额外的访问范围