如何使用 Identity Server 4 (JWT) 进行基于角色的 Web API 授权

Posted

技术标签:

【中文标题】如何使用 Identity Server 4 (JWT) 进行基于角色的 Web API 授权【英文标题】:How to do Role-based Web API Authorization using Identity Server 4 (JWT) 【发布时间】:2018-12-05 16:04:24 【问题描述】:

这对我来说是全新的,我仍在努力解决它。我已经设置了 IDP(Identity Server 4),并且能够配置客户端对其进行身份验证(Angular 6 App),并进一步对 API 进行身份验证(Asp.Net Core 2.0)。一切似乎都很好。

这是 IDP 中的客户端定义:

new Client
            
                ClientId = "ZooClient",
                ClientName = "Zoo Client",
                AllowedGrantTypes = GrantTypes.Implicit,
                AllowAccessTokensViaBrowser = true,
                RequireConsent = true,

                RedirectUris           =  "http://localhost:4200/home" ,
                PostLogoutRedirectUris =  "http://localhost:4200/home" ,
                AllowedCorsOrigins =  "http://localhost:4200" ,

                AllowedScopes =
                
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    IdentityServerConstants.StandardScopes.Email,
                    IdentityServerConstants.StandardScopes.Phone,
                    IdentityServerConstants.StandardScopes.Address,
                    "roles",
                    "ZooWebAPI"
                
            

我在客户端中请求以下范围: 'openid 个人资料电子邮件角色 ZooWebAPI'

WebAPI 是这样设置的:

    public void ConfigureServices(IServiceCollection services)
    
        services
            .AddMvcCore()
            .AddJsonFormatters()
            .AddAuthorization();

        services.AddCors();
        services.AddDistributedMemoryCache();

        services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(options =>
            
                options.Authority = "https://localhost:44317";
                options.RequireHttpsMetadata = false;
                options.ApiName = "ZooWebAPI";    
            );


    

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    
        if (env.IsDevelopment())
        
            app.UseDeveloperExceptionPage();
        

        app.UseCors(policy =>
        
            policy.WithOrigins("http://localhost:4200");
            policy.AllowAnyHeader();
            policy.AllowAnyMethod();
            policy.AllowCredentials();
            policy.WithExposedHeaders("WWW-Authenticate");
        );

        app.UseAuthentication();
        app.UseMvc();
    

通过使用 [Authorize],我成功地保护了 API:

[Route("api/[controller]")]
    [Authorize]
    public class ValuesController : Controller
    
        // GET api/values
        [HttpGet]
        public ActionResult Get()
        
            return new JsonResult(User.Claims.Select(
                c => new  c.Type, c.Value ));
        
    

一切正常,如果客户端未通过身份验证,浏览器转到 IDP,需要身份验证,使用访问令牌重定向回来,然后将访问令牌用于成功进行的 API 调用。

如果我查看 User 对象中的 Claims,我可以看到一些信息,但我没有任何用户信息。我可以看到范围等,但例如没有角色。从我读到的内容来看,这是可以预料的,API 不应该关心用户在调用它,但是我将如何通过基于角色来限制 API 调用呢?还是会完全违反规范?

IDP 有一个返回所有用户信息的 userinfo 端点,我认为这将在 WebAPI 中使用,但再次,从一些阅读来看,它的意图是从仅限客户端。

无论如何,我想根据特定用户的角色来限制 Web API 调用。有没有人有什么建议,cmets?另外,我想知道是哪个用户拨打电话,我该怎么做?

JWT 示例:

谢谢

【问题讨论】:

【参考方案1】:

根据我从您的信息中了解到的情况,我可以告诉您以下内容。

您正在通过外部提供程序登录:Windows 身份验证。 您正在定义一些范围以将某些内容传递给指示对特定资源的访问权限的令牌。

您所说的 User 对象,是从访问令牌中填充的 User 类。由于默认情况下访问令牌不包括用户配置文件声明,因此您在 User 对象上没有它们。这与在用户原则上提供用户名的情况下直接使用 Windows 身份验证不同。

您需要采取额外的行动来根据用户登录提供授权。 您可以在以下几点添加授权逻辑:

您可以在 Identityserver 的配置中定义的自定义范围定义声明。恕我直言,这是不可取的,因为它固定到登录方法而不是用户登录。

您可以使用 ClaimsTransformation(请参阅下面的链接)。这允许您将声明添加到方法开始时可用的声明列表中。这有一个缺点(对某些人来说是肯定的),这些额外的声明不会添加到访问令牌本身,只有在评估令牌的后端,才会在您的代码处理请求之前添加这些声明.

如何检索这些声明取决于您的业务需求。

如果你需要用户信息,你必须调用 Identityserver 的 userinfo 端点至少知道用户名。这就是该端点的用途。在此基础上,您可以使用自己的逻辑来确定该用户拥有的“角色”。

例如,我们创建了一个单独的服务,可以根据用户和 accesstoken 中包含的范围配置和返回“角色”声明。

UseClaimsTransformation .NET Core

UseClaimsTransformation .NET Full framework

【讨论】:

以上是关于如何使用 Identity Server 4 (JWT) 进行基于角色的 Web API 授权的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Identity Server 4 (JWT) 进行基于角色的 Web API 授权

Identity Server 4 - 如何解决客户端注销后访问令牌仍然有效?

Identity Server 4 没有可用于令牌的安全令牌验证器

Identity Server 4 Admin 开源项目

使用 Identity Server 4 和 ASP.NET Identity 添加外部登录

Identity Server 4 - Hybrid Flow - 保护API资源