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

时间:2018-06-26 20:57:39

标签: asp.net-web-api asp.net-core jwt identityserver4

这对我来说是新事物,我仍在努力将其包裹住。我已经设置了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();
    }

通过使用[授权],我成功地保护了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中使用它,但是再次从阅读中看来,它的意图是要从WebAPI调用该端点。仅限客户。

无论如何,我想基于特定用户的角色来限制Web API调用。有人有任何建议,意见吗?另外,我想知道是什么用户在拨打电话,怎么办?

JWT示例:

enter image description here

谢谢

1 个答案:

答案 0 :(得分:0)

根据我可以从您的信息中学到的东西,我可以告诉以下内容。

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

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

您需要采取其他措施来根据用户登录提供授权。 您可以在其中添加授权逻辑的几点:

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

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

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

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

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

UseClaimsTransformation .NET Core

UseClaimsTransformation .NET Full framework