首页 > 解决方案 > IdentityServer:具有不同授权类型的多个客户端,策略无法正常工作

问题描述

我有一个具有以下“看起来像”配置的身份服务器设置:

        return new List<Client>
        {
            new Client
            {
                [...]
                AllowedGrantTypes = GrantTypes.Implicit,
                [....]
            },
            new Client
            {
                [...]
                AllowedGrantTypes = GrantTypes.ClientCredentials,
                [....]
            }
        };

和这样注释的控件:

    [Route("api/forms")]
    [ApiController]
    [Authorize(Policy = "user.api.portfolio.manager")]
    [Authorize(Policy = "application.api.portfolio.manager")]
   public class FormsController : ControllerBase
   {
      [...]
   }

和一个政策

        private System.Action<AuthorizationOptions> AddJwtAuthorizationPolicyForRole()
        {
            return options => { options.AddPolicy("**POLICY_FOR_GRANT_IMPLICIT**", policy => { 
                policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme); 
                policy.RequireAuthenticatedUser();
                policy.RequireClaim(ClaimTypes.Role, "USER_ACCESSIBLE");
            }); 
            };
        }

        private System.Action<AuthorizationOptions> AddJwtAuthorizationPolicyForRole()
        {
            return options => { options.AddPolicy("**POLICY_FOR_CLIENT_CREDENTIALS**", policy => { 
                policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme); 
                policy.RequireAuthenticatedUser();
            }); 
            };
        }

所以我想实现:

使用 GrantType.ClientCredentials 的客户端无需任何进一步的需求即可访问控制器。使用隐式模式的客户端必须具有角色 USER_ACCESSIBLE

如果配置如上所示,则必须应用两种策略 -> 两种授权类型均失败。

如何使用 IdentityServer 实现所描述的行为,每个授权类型可能有一个独立的策略,以便应用?

在此先感谢您的帮助。

标签: c#.netasp.net-coreidentityserver4policies

解决方案


最简单的解决方案是为 Implicit + ClientCredential 添加另一个单一策略来实现 OR 条件的逻辑。

或者您可以创建一个自定义属性,例如:

  • MultiplePolicysAuthorizeAttribute

    public class MultiplePolicysAuthorizeAttribute : TypeFilterAttribute
    {
         public MultiplePolicysAuthorizeAttribute(string policys, bool isAnd = false) : base(typeof(MultiplePolicysAuthorizeFilter))
         {
             Arguments = new object[] { policys, isAnd };
         }
    }
    
  • MultiplePolicysAuthorizeFilter

    public class MultiplePolicysAuthorizeFilter : IAsyncAuthorizationFilter
    {
        private readonly IAuthorizationService _authorization;
        public string Policys { get; private set; }
        public bool IsAnd { get; private set; }
    
        public MultiplePolicysAuthorizeFilter(string policys, bool isAnd, IAuthorizationService authorization)
        {
           Policys = policys;
           IsAnd = isAnd;
           _authorization = authorization;
        }
    
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var policys = Policys.Split(";").ToList();
            if (IsAnd)
            {
                foreach (var policy in policys)
                {
                    var authorized = await _authorization.AuthorizeAsync(context.HttpContext.User, policy);
                    if (!authorized.Succeeded)
                    {
                        context.Result = new ForbidResult();
                        return;
                    }
    
                }
             }
             else
             {
                foreach (var policy in policys)
                {
                     var authorized = await _authorization.AuthorizeAsync(context.HttpContext.User, policy);
                     if (authorized.Succeeded)
                     {
                         return;
                     }
    
                }
                context.Result = new ForbidResult();
                return;
            }
         }
    }
    

如果操作需要匹配策略之一(或):

[MultiplePolicysAuthorize("POLICY_FOR_GRANT_IMPLICIT;POLICY_FOR_CLIENT_CREDENTIALS")]

如果操作需要匹配所有策略(和):

[MultiplePolicysAuthorize("POLICY_FOR_GRANT_IMPLICIT;POLICY_FOR_CLIENT_CREDENTIALS",true)]

代码示例参考:https ://stackoverflow.com/a/52639938/5751404


推荐阅读