繁体   English   中英

具有范围特定路由的 C# Web API

[英]C# Web API with Scope Specific Routes

我使用 IdentityServer4 作为身份提供者,我的 C# Web API(用于用户)通过以下方式保护:

services.AddAuthentication(Authentication.Bearer)
  .AddJwtBearer(Authentication.Bearer, options =>
  {
    options.Authority = Configuration.GetSection("IdentityServer:Authority").Value;
    options.Audience = Scopes.UsersService;
  });

和控制器上的[Authorize] 因此,任何想要在 UsersService 中调用路由的人都需要一个以“usersservice”为范围的经过验证的令牌。

我想通过范围开辟几条路线。 因此,如果路由调用者具有“usersservice”范围,他们仍然可以访问所有路由。 但是,如果他们具有“usersservice.read”范围,他们将只能访问我指定用于读取访问的路由。 我怎样才能做到这一点?

解决方案

Alpha75 列出了一系列关于如何解决此问题的选项。 我最终选择了 AddPolicy 路线。 这就是我为我的用户服务实现它的方式。 我去掉了“userservice”作用域,增加了两个作用域“usersservice.all”和“usersservice.read”,而不是单纯的依赖观众。

services.AddAuthentication(Authentication.Bearer)之后的 Startup.cs 中:

services.AddAuthorization(options =>
  options.AddPolicy("all", policy =>
    policy.RequireClaim("scope", "usersservice.all")
    )
  );

services.AddAuthorization(options =>
  options.AddPolicy("read", policy => 
    policy.RequireClaim("scope", "usersservice.all", "usersservice.read")
    )
  );

然后在读取操作上,我有[Authorize(Policy = "read")]并且在所有其他操作上,我有[Authorize(Policy = "all")] 注意:“usersservice.all”在“读取”策略中,因此任何具有 all 范围的调用者也可以访问读取操作。

api

一件事是 Api 资源,另一件事是 Api 资源的 Api 范围。 在您的 API 处理程序中,您必须配置您的 Api 资源。

options.Audience = "usersservice";

要按范围保护,您可以使用几种方法

  • 保护动作方法:

     [HttpGet] [RequiredScope("usersservice.write")] public IEnumerable<TodoItem> Get() { // Do the work and return the result. // ... }
  • 保护控制器:

     [Authorize] [RequiredScope("usersservice.read")] public class TodoListController : Controller { ... }
  • 有条件地使用扩展方法 VerifyUserHasAnyAcceptedScope

     [HttpGet] public IEnumerable<TodoItem> Get() { HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi); // Do the work and return the result. // ... }
  • 基于政策( Duende 文档中的示例):

     // 1. In ConfigureServices services.AddAuthorization(options => { options.AddPolicy("read_access", policy => policy.RequirementClaim("scope", "usersservice.read"); }); // 2.a. In the Controller declaratively [Authorize("read_access")] public async Task<IActionResult> Get() { // rest omitted } // 2.b. Or In the Controller imperatively public class DataController : ControllerBase { IAuthorizationService _authz; public DataController(IAuthorizationService authz) { _authz = authz; } public async Task<IActionResult> Get() { var allowed = _authz.CheckAccess(User, "read_access"); // rest omitted } }
  • 基于策略但使用自定义要求 这比其他人更灵活,但如果您只想检查范围,则可能没有必要。

身份服务器配置

根据 IdentityServer4 版本,您将对关系 ApiResource <-> ApiScope 有不同的模型:

...从 v4 开始,范围有自己的定义,并且可以有选择地被资源引用。 在 v4 之前,范围始终包含在资源中。

IdentityServer4 文档

如果你使用 v4,你可以有这样的配置(你可能会有一个带有你的配置的数据库):

public static IEnumerable<ApiScope> GetApiScopes()
{
    return new List<ApiScope>
    {
        // userservice API specific scopes
        new ApiScope(name: "usersservice.read",   displayName: "Reads user data"),
        new ApiScope(name: "usersservice.write",    displayName: "Writes user data"),

        // another API specific scopes
        new ApiScope(name: "another.read",    displayName: "Reads another data"),            

        // shared scope
        new ApiScope(name: "manage", displayName: "Provides administrative access to user and another data")
    };
}

public static readonly IEnumerable<ApiResource> GetApiResources()
{
    return new List<ApiResource>
    {
        new ApiResource("usersservice", "Users Service API")
        {
            Scopes = { "usersservice.read", "usersservice.write", "manage" }
        },

        new ApiResource("anotherservice", "Another API")
        {
            Scopes = { "another.read", "manage" }
        }
    };
}

请注意,使用此模型,您可以在资源之间“共享”范围,尽管它是可选的。 在示例中,范围“管理”允许访问这两个服务。 这在 v4 之前是不可能的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM