zoukankan      html  css  js  c++  java
  • IdentityServer4 指定角色授权(Authorize(Roles="admin"))

    1. 业务场景

    IdentityServer4 授权配置Client中的AllowedScopes,设置的是具体的 API 站点名字,也就是使用方设置的ApiName,示例代码:

    //授权中心配置
    new Client
    {
        ClientId = "client_id_1",
        AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
        AllowOfflineAccess = true,
        AccessTokenLifetime = 3600 * 6, //6小时
        SlidingRefreshTokenLifetime = 1296000, //15天
        ClientSecrets =
        {
            new Secret("secret".Sha256())
        },
        AllowedScopes = 
        {
            "api_name1"
        },
    }
    
    //API 服务配置
    app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
    {
        Authority = $"http://localhost:5000",
        ApiName = "api_name1",
        RequireHttpsMetadata = false
    });
    

    上面两个api_name1配置要一致,问题来了,因为授权中心的scope配置是整个 API 服务,如果我们存在多个Client配置,比如一个前台和后台,然后都需要访问api_name1,就会出现一些问题。

    比如,api_name1服务中的一个接口服务配置代码:

    [Authorize()]
    [Route("api/values")]
    [HttpGet]
    public IActionResult Get()
    {
        return Ok();
    }
    

    Authorize()的配置,说明api/values接口需要授权后访问,如果授权中心配置了两个Client(前台和后台),并且scope都包含了api_name1,现在就会出现两种情况:

    1. 前台Client和后台Client,都需要授权后访问api/values接口:没有问题。
    2. 前台Client不需要授权后访问,后台Client需要授权后访问:有问题,前台Client没办法访问了,因为api/values接口设置了Authorize()

    其实,说明白些,就是该如何让 API 服务指定Client授权访问?比如:[Authorize(ClientId = 'client_id_1')]

    2. 解决方案

    没有[Authorize(ClientId = 'client_id_1')]这种解决方式,不过可以使用[Authorize(Roles = 'admin')]

    授权中心的ResourceOwnerPasswordValidator代码,修改如下:

    public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
    {
        private readonly IUserService _userService;
    
        public ResourceOwnerPasswordValidator(IUserService userService)
        {
            _userService = userService;
        }
    
        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
        {
            var user = await _userService.Login(context.UserName, context.Password);
            if (user != null)
            {
                var claims = new List<Claim>() { new Claim("role", "admin") }; //根据 user 对象,设置不同的 role
                context.Result = new GrantValidationResult(user.UserId.ToString(), OidcConstants.AuthenticationMethods.Password, claims);
            }
        }
    }
    

    授权中心的startup配置,修改如下

    var builder = services.AddIdentityServer();
    builder.AddTemporarySigningCredential()
            //.AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(new List<ApiResource>
            {
                new ApiResource("api_name1", "api1"){ UserClaims = new List<string> {"role"}}, //增加 role claim
                new ApiResource("api_name2", "api2"){ UserClaims = new List<string> {"role"}}
            })
            .AddInMemoryClients(Config.GetClients());
    

    API 服务接口,只需要配置如下:

    [Authorize()]
    [Route("api/values")]
    [HttpGet]
    public IActionResult Get()
    {
        return Ok();
    }
    
    [Authorize(Roles = "admin")]
    [Route("api/values2")]
    [HttpGet]
    public IActionResult Get2()
    {
        return Ok();
    }
    
    [Authorize(Roles = "admin,normal")]
    [Route("api/values3")]
    [HttpGet]
    public IActionResult Get3()
    {
        return Ok();
    }
    

    需要注意的是,api/values接口虽然没有设置具体的Roles,但每个Role都可以访问。

  • 相关阅读:
    VS2015, .NET 4.6, C# 6.0, F# 4.0等重量级产品正式上线
    Visual Studio 2015正式发布
    持续集成并不能消除 Bug,而是让它们非常容易发现和改正(转)
    如何用Excel直接查询Oracle中的数据(转)
    HTTP必知必会(转)
    二叉树的友好实现(转)
    TortoiseGit push失败原因小结(转)
    Android
    对JAVA Bean使用PropertyDescriptor反射调用JAVA方法
    关于MSHTML
  • 原文地址:https://www.cnblogs.com/xishuai/p/identityserver4-apiresource-userclaim-role-authorize.html
Copyright © 2011-2022 走看看