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

8

我想创建一个自定义的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方法中访问claim。 - programtreasures
2个回答

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

1
嗨@AlbertK。感谢您的回复。他帮了我很多。我只需要更改3行代码。 1)authorizationFilterContext.HttpContext.RequestServices.GetRequiredService<IAuthorizationPolicyProvider>() 2)authorizationPolicy.Requirements.OfType<ClaimsAuthorizationRequirement>().FirstOrDefault() 3)policyProvider.GetPolicyAsync(Policy) - avechuche

6

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

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

    }
}

希望这能帮助到您…

感谢您在使用IAsyncAuthorizationFilter进行异步支持的方法中给出的提示(例如,用于验证的外部调用将是异步的)。 - CajunCoding

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接