1

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

[ApiController]
[RequiredScope("AnyRandomName")]
public class MyApiController : ControllerBase
{

更新

这是我的 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();
        });
    }
}

这是我的 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()
    {
        ...

请注意,我在控制器级别应用了此处的属性。但是,如果我将它们移到操作级别并没有什么区别——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");
    });
});

这是 access_token 标头

在此处输入图像描述

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

4

2 回答 2

1

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

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

        options.AddPolicy("ViewReports", policy =>
                          policy.RequireAuthenticatedUser()
                                .RequireRole("Finance")
                                .RequireRole("Management")
                          );                  
    });

该政策规定用户必须经过身份验证并同时担任这两个角色。在此示例中,RequireAuthenticatedUser() 是可选的。

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

[Authorize(Policy = "ViewReports")]
public IActionResult ViewReports()
{
    return View();
}

要使角色声明生效,您必须通过执行以下操作定义令牌中角色声明的名称:

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

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

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

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

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

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

于 2022-01-07T17:38:00.320 回答
0

我的代码:

安装这两个包:

<PackageReference Include="Microsoft.Azure.AppConfiguration.AspNetCore" Version="4.5.1" />
<PackageReference Include="Microsoft.Identity.Web" Version="1.21.1" />

Startup.cs,在ConfigureServices方法中添加代码。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd");
    services.AddControllers();
}

不要忘记Configure方法中的这两行:

app.UseAuthentication();
app.UseAuthorization();

我的测试控制器:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web.Resource;
using System.Collections.Generic;

namespace WebApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    [RequiredScope("User.Read")]
    public class HomeController : ControllerBase
    {
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "value1", "value2" };
        }

        [HttpPost]
        public string getRes() {
            return "hello world";
        }
    }
}

测试结果 :

在此处输入图像描述 在此处输入图像描述

==================================================== =============

要保护 ASP.NET 或 ASP.NET Core Web API,您必须将 [Authorize] 属性添加到以下项目之一:

控制器本身,如果您希望所有控制器操作都受到保护您的 API 的单个控制器操作

根据本节的例子,

[Authorize]在行前添加[RequiredScope("AnyRandomName")]

[ApiController]
[Authorize]
[RequiredScope("AnyRandomName")]
public class MyApiController : ControllerBase
{
于 2022-01-06T01:58:55.330 回答