自定义授权属性-ASP .NET Core 2.2

时间:2019-03-09 16:25:38

标签: c# asp.net-core

我想创建一个自定义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 ...
}

2 个答案:

答案 0 :(得分:3)

此属性采用字符串数组,在我的情况下是必需的。我需要将不同的用户角色传递给该属性,并根据一些自定义逻辑返回结果。

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()

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

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();

    }
}

希望有帮助。

答案 1 :(得分:1)

您可以使用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));
            }
        }
    }
}