基于策略的授权失败时需要返回一些原因

问题描述 投票:0回答:1

首先一些代码:

builder
    .Services
    .AddAuthorization(options =>
    {
        options.AddPolicy("IsLoggedIn", policy =>
        {
            policy.RequireClaim(StoreApi.Properties.Resources.UserName);
            policy.RequireClaim(StoreApi.Properties.Resources.UserID);
        });
        options.AddPolicy("IsCustomer", policy =>
        {
            policy.RequireClaim(StoreApi.Properties.Resources.UserType, nameof(Customer));
        });
        options.AddPolicy("IsAdministrator", policy =>
        {
            policy.RequireClaim(StoreApi.Properties.Resources.UserType, nameof(Administrator));
        });
        options.AddPolicy("IsApplication", policy =>
        {
            policy.RequireClaim(StoreApi.Properties.Resources.UserType, nameof(Application));
        });
        options.AddPolicy("IsSystem", policy =>
        {
            policy.RequireClaim(StoreApi.Properties.Resources.UserType, nameof(Application), nameof(Administrator));
        });
        options.AddPolicy("HasCart", policy =>
        {
            policy.RequireClaim(StoreApi.Properties.Resources.UserCart);
        });
    });

我有一堆基于声明的策略,并且声明是在资源中定义的,而有些需要具有特定的值。这些声明来自 JWT 令牌,整个事情是一个简化的网络商店。这些政策运作良好,除了一个问题......
当用户未能满足策略时,他们会收到 403“禁止”消息,但不会解释问题所在。因为我有多个政策,所以我想知道哪个政策失败了。
那么,我如何确保 403 向客户端提供这些额外数据?

c# asp.net-web-api policy
1个回答
0
投票

我认为您应该根据

this
文章实现您自己的IAuthorizationMiddlewareResultHandler

示例:

政策:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("Admin",
        policy =>
        {
            policy.Requirements.Add(new RolesAuthorizationRequirement(new[] { "Admin" }));
            policy.Requirements.Add(new ClaimsAuthorizationRequirement("MyClaim", new[] { "Test" }));
        });
});
[HttpGet]
[Authorize(Policy = "Admin")]
public async Task<IActionResult> Get() => Ok(true);

定制

IAuthorizationMiddlewareResultHandler

public class MyAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
    private readonly AuthorizationMiddlewareResultHandler defaultHandler = new();

    public async Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy,
        PolicyAuthorizationResult authorizeResult)
    {
        // Fall back to the default implementation.
        await defaultHandler.HandleAsync(next, context, policy, authorizeResult);

        //Have to write to body after default implementation because is sets Http Code 
        if (!authorizeResult.Succeeded)
        {
            string? text = authorizeResult.AuthorizationFailure?.FailedRequirements.Aggregate(new StringBuilder(),
                (builder, reason) => builder.Append(reason + Environment.NewLine), builder => builder.ToString());
            if (!string.IsNullOrWhiteSpace(text))
                await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes(text));
        }
    }
}

它的注册

builder.Services.AddSingleton<IAuthorizationMiddlewareResultHandler, 
                                MyAuthorizationMiddlewareResultHandler>();

完成所有这些步骤后,调用端点后的结果将是状态代码 403 的响应:

RolesAuthorizationRequirement:User.IsInRole must be true for one of the following roles: (Admin)
ClaimsAuthorizationRequirement:Claim.Type=MyClaim and Claim.Value is one of the following values: (Test)

如果您想自定义响应文本,您应该使用

FailedRequirements
FailureReasons
authorizeResult.AuthorizationFailure
属性。

来源:

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.