【问题标题】:Custom Authorize attribute - ASP .NET Core 2.2自定义授权属性 - ASP .NET Core 2.2
【发布时间】:2019-07-31 10:37:09
【问题描述】:

我想创建一个自定义 Authorize 属性,以便能够在失败时发送个性化响应。有很多例子,但我找不到我要找的东西。 注册保单时,我添加了“索赔”。是否可以在自定义属性中访问已注册的声明而无需通过参数传递声明?或者是否有可能知道索赔检查是否发生,如果没有,返回个性化回复?谢谢!

public static void AddCustomAuthorization(this IServiceCollection serviceCollection)
{
    serviceCollection.AddAuthorization(x =>
    {
        x.AddPolicy(UserPolicy.Read,
            currentPolicy => currentPolicy.RequireClaim(UserClaims.Read));
    });
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext authorizationFilterContext)
    {
        if (authorizationFilterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            if (!authorizationFilterContext.HttpContext.User.HasClaim(x => x.Value == "CLAIM_NAME")) // ACCESS TO REGISTER CLAIM => currentPolicy => currentPolicy.RequireClaim(UserClaims.Read)
            {
                authorizationFilterContext.Result = new ObjectResult(new ApiResponse(HttpStatusCode.Unauthorized));
            }
        }
    }
}

[HttpGet]
[CustomAuthorizeAttribute(Policy = UserPolicy.Read)]
public async Task<IEnumerable<UserDTO>> Get()
{
    return ...
}

【问题讨论】:

  • 您必须能够通过 OnAuthorization 方法访问声明

标签: c# asp.net-core


【解决方案1】:

这个属性接受一个字符串数组,这在我的例子中是需要的。我需要将不同的用户角色传递给这个属性并根据一些自定义逻辑返回结果。

public class CustomAuthFilter : AuthorizeAttribute, IAuthorizationFilter
{
    public CustomAuthFilter(params string[] args)
    {
        Args = args;
    }

    public string[] Args { get; }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        //Custom code ...

        //Resolving a custom Services from the container
        var service = context.HttpContext.RequestServices.GetRequiredService<ISample>();
        string name = service.GetName(); // returns "anish"

        //Return based on logic
        context.Result = new UnauthorizedResult();
    }
}

你可以使用这个属性来装饰你的控制器,如下所示

 [CustomAuthFilter("Anish","jiya","sample")]
 public async Task<IActionResult> Index()

Sample 是一个返回硬编码字符串的类

public class Sample : ISample
{
    public string GetName() => "anish";
}

services.AddScoped(); //注册ISample,Sample作为作用域。

对于异步支持,请使用 IAsyncAuthorizationFilter

public class CustomAuthFilter : AuthorizeAttribute, IAsyncAuthorizationFilter
{

    public CustomAuthFilter(params string[] args)
    {
        Args = args;
    }

    public string[] Args { get; }

    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        //DO Whatever...

        //Resolve Services from the container
        var service = context.HttpContext.RequestServices.GetRequiredService<ISample>();
        var httpClientFactory = context.HttpContext.RequestServices.GetRequiredService<IHttpClientFactory>();
        string name = service.GetName();

        using var httpClient = httpClientFactory.CreateClient();

        var resp = await httpClient.GetAsync("https://jsonplaceholder.typicode.com/todos/1");
        var data = await resp.Content.ReadAsStringAsync();

        //Return based on logic
        context.Result = new UnauthorizedResult();

    }
}

希望对您有所帮助..

【讨论】:

    【解决方案2】:

    您可以使用IAuthorizationPolicyProvider 获取策略,然后使用ClaimsAuthorizationRequirement.ClaimType 获取声明名称。而且由于它有异步 API,所以最好使用IAsyncAuthorizationFilter 而不是IAuthorizationFilter。试试这个:

    public class CustomAuthorizeAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
    {
        public async Task OnAuthorizationAsync(AuthorizationFilterContext authorizationFilterContext)
        {
            var policyProvider = authorizationFilterContext.HttpContext
                .RequestServices.GetService<IAuthorizationPolicyProvider>();
            var policy = await policyProvider.GetPolicyAsync(UserPolicy.Read);
            var requirement = (ClaimsAuthorizationRequirement)policy.Requirements
                .First(r => r.GetType() == typeof(ClaimsAuthorizationRequirement));
    
            if (authorizationFilterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                if (!authorizationFilterContext.HttpContext
                  .User.HasClaim(x => x.Value == requirement.ClaimType))
                {
                    authorizationFilterContext.Result = 
                       new ObjectResult(new ApiResponse(HttpStatusCode.Unauthorized));
                }
            }
        }
    }
    

    【讨论】:

    • 嗨@AlbertK。谢谢回复。他帮了我很多。我只需要更改 3 行代码。 1) authorizationFilterContext.HttpContext.RequestServices.GetRequiredService () 2) authorizationPolicy.Requirements.OfType()。 FirstOrDefault() 3) policyProvider.GetPolicyAsync(Policy)
    猜你喜欢
    • 1970-01-01
    • 2021-07-19
    • 2020-04-28
    • 2017-05-22
    • 1970-01-01
    • 2021-05-07
    • 2020-05-04
    • 2017-09-16
    • 1970-01-01
    相关资源
    最近更新 更多