为什么RequiredScope属性没有任何作用?

Ale*_*exu 6 api-authorization asp.net-core-webapi

根据此 Microsoft 文档,您应该能够将 [RequiredScope("SomeScopeName")] 等属性应用到控制器级别或操作级别以保护 API。但是当我在 API 中尝试它时,它似乎根本没有任何效果 - 无论我使用什么范围名称(我确保令牌中没有该名称的范围),我总是正确的进入我应该失败的 API 操作。但与此同时,我的策略属性,例如 [Authorize(Policy = "PolicyName")],工作得很好。我缺少什么?

[ApiController]
[RequiredScope("AnyRandomName")]
public class MyApiController : ControllerBase
{
Run Code Online (Sandbox Code Playgroud)

更新

这是我的 Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        IdentityModelEventSource.ShowPII = true; 
        services.AddControllers();

        services.AddSwaggerGen(opt =>
        {
            opt.CustomSchemaIds(type => type.ToString() + type.GetHashCode()); 
        });

        services.Configure<HostOptions>(Configuration.GetSection(HostOptions.HOST));

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 
        JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();
        services.AddAuthentication("Bearer").AddJwtBearer(options =>
        {
            options.Authority = Configuration[HostOptions.IDENTITYGATEWAY];
            options.SaveToken = true;
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateAudience = false
            };
        });

        services.AddTransient<gRPCServiceHelper>();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseExceptionHandler("/error-local-development");
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "GroupDemographicEFCore v1"));
        }
        else
        {
            app.UseExceptionHandler("/error");
        }

        app.UseHttpsRedirection();
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 API 控制器

[ApiController]
[Authorize]
[RequiredScope("NoSuchScope")]
public class MyApiController : ControllerBase
{
    public MyApiController([NotNull] IConfiguration configuration, [NotNull] ILogger<MyApiController> logger,
        [NotNull] gRPCServiceHelper helper) : base(configuration, logger, helper)
    {
    }

    [HttpGet]
    [Route("/clients/summary")]
    public async Task<IActionResult> ClientsSummaryGet()
    {
        ...
Run Code Online (Sandbox Code Playgroud)

请注意,我在控制器级别应用了此处的属性。但是,如果我将它们移至操作级别,也没有什么区别——RequiredScope 属性总是被忽略。

更新1

我在上次帖子更新中遗漏了 AddAuthorization,因为我认为它与我的问题无关。我现在将其添加回来,其中包含我使用的一些策略。再说一次,这些政策都运行良好,我不明白这与我遇到的问题有什么关系。

services.AddAuthorization(options =>
{
    options.AddPolicy("OperatorCode", policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.RequireClaim("OperatorCode");
    });
    options.AddPolicy("OperatorCode:oprtr0", policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.RequireClaim("OperatorCode", "oprtr0");
    });
    options.AddPolicy("Role:User+OperatorCode:oprtr0", policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.RequireRole("User");
        policy.RequireClaim("OperatorCode", "oprtr0");
    });
    options.AddPolicy("Role:Admin||Role:User", policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.RequireRole("Admin", "User");
    });
});
Run Code Online (Sandbox Code Playgroud)

这是 access_token 标头

在此输入图像描述

这是access_token的主体 在此输入图像描述 在此输入图像描述

小智 10

我们需要做的就是添加

services.AddRequiredScopeAuthorization();

为了让 RequireScopeAttrubute 发挥作用,无论如何,这都是AddMicrosoftIdentityWebApiAuthentication在幕后让它发挥作用的。


And*_*ndy 1

您需要做的是在 Startup.cs 中添加和配置授权,如下所示:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {

        options.AddPolicy("ViewReports", policy =>
                          policy.RequireAuthenticatedUser()
                                .RequireRole("Finance")
                                .RequireRole("Management")
                          );                  
    });
Run Code Online (Sandbox Code Playgroud)

该策略规定用户必须经过身份验证并且具有两种角色。在此示例中,RequireAuthenticatedUser() 是可选的。

然后您可以使用该策略,例如:

[Authorize(Policy = "ViewReports")]
public IActionResult ViewReports()
{
    return View();
}
Run Code Online (Sandbox Code Playgroud)

要使角色声明发挥作用,您必须在令牌中定义角色声明的名称,方法如下:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
     .AddJwtBearer(options =>
     {
           options.TokenValidationParameters.NameClaimType = "name";
           options.TokenValidationParameters.RoleClaimType = "role";
     });
Run Code Online (Sandbox Code Playgroud)

否则可能找不到该角色,因为 OpenIDConnect 和 Microsoft 对于该声明的名称有不同的看法。

从长远来看,使用策略将为您提供更好、更干净的代码,因为如果您将来需要更改范围,则需要更新所有控制器类。通过策略,您可以在一处更改它。

另外,根据 GitHub 上的这个问题,它说:

requiredScopes 仅检查 scp 或 http://schemas.microsoft.com/identity/claims/scope声明。

这意味着您可能需要执行一些声明转换(重命名)才能将RequiredScope 映射到访问令牌中的范围声明。

为了补充这个答案,我写了一篇博客文章,更详细地介绍了这个主题:调试 ASP.NET Core 中的 OpenID Connect 声明问题

  • 为什么不在这里使用策略而不是 [RequiredScope("AnyRandomName")]?如果政策有效,那么到处都使用政策吗?使用策略比硬编码 requiredscope 更好... (2认同)