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

ave*_*che 7 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 ...
}
Run Code Online (Sandbox Code Playgroud)

Alb*_*rtK 10

您可以使用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));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ani*_*ish 5

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用此属性装饰您的控制器,如下所示

 [CustomAuthFilter("Anish","jiya","sample")]
 public async Task<IActionResult> Index()
Run Code Online (Sandbox Code Playgroud)

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

public class Sample : ISample
{
    public string GetName() => "anish";
}
Run Code Online (Sandbox Code Playgroud)

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

    }
}
Run Code Online (Sandbox Code Playgroud)

希望有帮助..