如何获取我在ASP.NET核心的Startup.ConfigureServices中添加的所有授权策略?

h5qlskok  于 2023-08-08  发布在  .NET
关注(0)|答案(2)|浏览(150)

在我的Asp.NET Core WebApi应用程序中,我想为ViewModel中的属性添加权限,然后自定义一个ActionFilter来过滤respone值。如果用户没有权限,则该属性将被回调值替换。现在,我想使用授权策略来检查权限。

如何获取我在Startup.ConfigureServices中添加的所有授权策略?

public void OnActionExecuted(ActionExecutedContext context)
    {
        if (!(context.Result is JsonResult)) return;
        var c = (JsonResult)context.Result;
        var pas = c.Value
              .GetType().GetTypeInfo()
              .GetProperties()
              .Where(p => p.GetCustomAttribute<PropertyPermissionAttribute>() != null)
              .Select(p =>
                {
                    var attr = p.GetCustomAttribute<PropertyPermissionAttribute>();
                    return (p, attr);
                });

        // ** How to Get All Policies ?? **

        foreach (var (p, a) in pas)
        {
            // Check Policies

            var cb = a.CallbackValue;
            if (cb!=null && p.PropertyType == cb.GetType())
            {
                p.SetValue(c.Value, cb);
            }
            else
            {
                p.SetValue(c.Value, null);
            }
        }
    }

字符串
或者是否有任何其他方式来实现视图模型属性的权限?

c6ubokkw

c6ubokkw1#

我认为这是不可能的。策略存储在私有字段中。See source .但是,我不明白为什么你需要所有的政策?如果将策略的名称存储在PropertyPermissionAttribute中,则可以从IAuthorizationPolicyProvider.GetPolicyAsync(string policyName)获取必要的策略。

pprl5pva

pprl5pva2#

是的,这是可以做到的,它建立在@Ivan R所说的基础上。我不得不做同样的事情。
首先创建一个具有SecurityStartup类的Console应用程序,该类继承自包含控制器的控制台应用程序中定义的Startup类。但是首先在Startup类中定义一个虚方法,它包含控制器
例如:

protected virtual void OutputEndpointInfo(IServiceCollection services){ }

字符串
现在在Startup.cs的ConfigureServies方法中调用此方法
例如:

OutputEndpointInfo(services);


您的SecurityStartup类应类似于:

public class SecurityStartup : Startup
{

    public static List<Endpoint> Endpoints{ get; set; }

    public SecurityStartup(IConfiguration configuration, IWebHostEnvironment environment) : base(configuration, environment)
    {
        Endpoints = new List<Endpoint>();
    }

    protected override void OutputEndpointInfo(IServiceCollection services)
    {
        var authorizationPolicyCollectionProvider = services
            .BuildServiceProvider()
            .GetRequiredService<IAuthorizationPolicyProvider>();

        var actionDescriptorCollectionProvider = services
            .BuildServiceProvider()
            .GetRequiredService<IActionDescriptorCollectionProvider>();

        var actionDescriptors = actionDescriptorCollectionProvider.ActionDescriptors.Items;

        foreach (var actionDescriptor in actionDescriptors)
        {
            if (actionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
            {
                string controllerName = controllerActionDescriptor.ControllerName;
                string actionName = controllerActionDescriptor.ActionName;

                var endpoint = new Endpoint
                {
                    Controller = controllerName,
                    Action = actionName
                };

                AuthorizeAttribute? authoriseAttribute = null;
                var authorisation = (controllerActionDescriptor?.EndpointMetadata
                    .Where(p => p.GetType() == typeof(AuthorizeAttribute)));

                if (authorisation != null && authorisation.Any())
                    authoriseAttribute = (AuthorizeAttribute)(authorisation).First();

                if (authoriseAttribute != null)
                {  
                    endpoint.Policy = authoriseAttribute.Policy;
                    if (endpoint.Policy != null)
                        endpoint.AuthorizationPolicy = authorizationPolicyCollectionProvider
                            .GetPolicyAsync(authoriseAttribute.Policy).Result;
                }

                Endpoints.Add(endpoint);
                Output.WriteLine(String.Empty, ConsoleColor.White);
            }
        }
    }
}


使用Endpoint类:

public class Endpoint
{
    public string? Controller { get; set; }
    public string? Action { get; set; }
    public string? Policy { get; set; }

    public AuthorizationPolicy? AuthorizationPolicy { get; set; }
}


现在在你的控制台应用程序中有这样的代码,它基本上迭代了所有的端点,并创建了一个集合,其中包含了你在控制器应用程序中设置的所有授权策略:
例如:

_host = Host.CreateDefaultBuilder()
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<SecurityStartup>();
                webBuilder.UseKestrel(options => options.AddServerHeader = false);
            }).UseSerilog((hostContext, loggerConfig) =>
            {
                ServiceInstanceInfo serviceInstanceInfo = hostContext.Configuration.Get<ServiceInstanceInfo>();
            })
            .Build();

    await DisplayUserSecurityEndpointData();


用一个方法(我喜欢从STS中为一个经过身份验证的用户获取一个访问令牌,并检查他们是否可以访问每个端点):

private static async Task DisplayUserSecurityEndpointData()
{
    var config = new SecurityConfig();
    var endpoints = SecurityStartup.Endpoints;
    var token = await SecurityService.GetAccessTokenPasswordFlow(config);
    var handler = new JwtSecurityTokenHandler();
    var jsonToken = handler.ReadToken(token);
    var securityToken = jsonToken as JwtSecurityToken;
    var claims = securityToken.Claims.ToList();

    endpoints.ForEach(p => {
        Output.Write($"{p.Controller} {p.Action}");

        if (p.AuthorizationPolicy != null && p.AuthorizationPolicy.Requirements.First() is ClaimsAuthorizationRequirement)
        {
            var policyClaim = (ClaimsAuthorizationRequirement)p.AuthorizationPolicy.Requirements.First();
            bool hasAccess = claims.Any(q => q.Type == policyClaim.ClaimType);

            Output.Write($" ACCESS: {claims.Any(q => q.Type == policyClaim.ClaimType)}",
                hasAccess ? ConsoleColor.Green : ConsoleColor.Red);
        }
    });
}


现在运行这个命令会给予每个端点的集合和所有的Auth内容,包括声明、角色等
我没有包括所有其他类等-但你得到的想法

相关问题