简体   繁体   English

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

[英]C# Web API with Scope Specific Routes

I am utilizing IdentityServer4 as the identity provider and my C# Web API (for Users) is protected via:我使用 IdentityServer4 作为身份提供者,我的 C# Web API(用于用户)通过以下方式保护:

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

and [Authorize] on the Controllers.和控制器上的[Authorize] So, anyone who wants to call the routes in the UsersService needs a verified token with "usersservice" as a scope.因此,任何想要在 UsersService 中调用路由的人都需要一个以“usersservice”为范围的经过验证的令牌。

I would like to open up a select few routes via scope.我想通过范围开辟几条路线。 So, if the route caller has the scope "usersservice", they would still have access to all routes.因此,如果路由调用者具有“usersservice”范围,他们仍然可以访问所有路由。 But, if they have the scope "usersservice.read", they would only have access to routes that I designate for read access.但是,如果他们具有“usersservice.read”范围,他们将只能访问我指定用于读取访问的路由。 How can I do this?我怎样才能做到这一点?

Solution :解决方案

Alpha75 listed a bunch of options as to how to resolve this. Alpha75 列出了一系列关于如何解决此问题的选项。 I ended up going with the AddPolicy route.我最终选择了 AddPolicy 路线。 This is how I implemented it for my usersservice.这就是我为我的用户服务实现它的方式。 I removed the "userservice" scope and added two scopes "usersservice.all" and "usersservice.read", and not simply rely on the audience.我去掉了“userservice”作用域,增加了两个作用域“usersservice.all”和“usersservice.read”,而不是单纯的依赖观众。

In Startup.cs after services.AddAuthentication(Authentication.Bearer) :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")
    )
  );

Then on the read actions, I have [Authorize(Policy = "read")] and on all other actions, I have [Authorize(Policy = "all")] .然后在读取操作上,我有[Authorize(Policy = "read")]并且在所有其他操作上,我有[Authorize(Policy = "all")] Note : "usersservice.all" is in the "read" policy so any caller with the all scope also has access to the read actions.注意:“usersservice.all”在“读取”策略中,因此任何具有 all 范围的调用者也可以访问读取操作。

Api api

One thing is the Api Resource and another thing are the Api Scopes of the Api Resource.一件事是 Api 资源,另一件事是 Api 资源的 Api 范围。 In the handler of your API you must to configure your Api Resource.在您的 API 处理程序中,您必须配置您的 Api 资源。

options.Audience = "usersservice";

And to protect by scope you can use several approaches :要按范围保护,您可以使用几种方法

  • Protect action method:保护动作方法:

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

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

     [HttpGet] public IEnumerable<TodoItem> Get() { HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi); // Do the work and return the result. // ... }
  • Based on policies ( examples in Duende documentation ):基于政策( 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 } }
  • Based on policies but using custom requirements .基于策略但使用自定义要求 This is more flexible than others but maybe is not necessary if you only want to check the scope.这比其他人更灵活,但如果您只想检查范围,则可能没有必要。

IdentityServer configuration身份服务器配置

Depending on the IdentityServer4 version you'll have different model for the relation ApiResource <-> ApiScope:根据 IdentityServer4 版本,您将对关系 ApiResource <-> ApiScope 有不同的模型:

...starting with v4, scopes have their own definition and can optionally be referenced by resources. ...从 v4 开始,范围有自己的定义,并且可以有选择地被资源引用。 Before v4, scopes were always contained within a resource.在 v4 之前,范围始终包含在资源中。

IdentityServer4 docs IdentityServer4 文档

If you use v4, you could have a configuration like this (you'll probably have a database with your configuration):如果你使用 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" }
        }
    };
}

Note that with this model you can "share" scopes between resources, although it is optional.请注意,使用此模型,您可以在资源之间“共享”范围,尽管它是可选的。 In the example, the scope "manage" allow access to both services.在示例中,范围“管理”允许访问这两个服务。 This wasn't possible before v4.这在 v4 之前是不可能的。

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

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