在哪里返回403禁止状态? [英] Where to return 403 Forbidden Status?

查看:50
本文介绍了在哪里返回403禁止状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用授权的路由来获取数据,但是由于该路由被禁止,因此我无法返回错误.

I'm using authorized routes to get data but since the Route is forbidden, I can't return an error.

[Route("getTotal")]
[HttpGet]
[Authorize(Roles = "Admin")]
public IActionResult GetTotalNumbers()
{
    var test = User.Claims;

    try
    {
        var logic = new DrainlockLogic(_appSettings);
        var ret = logic.GetTotalNumbers();
        return Ok(ret);
    }
    catch (Exception e)
    {
        return StatusCode(500, e);
    }
}

我的错误始终为空.

this.homeService.getGratingNumbers()
  .pipe(
    map(itemData => {
      return itemData.map(value => {
        // return new ListItem(value.id, value.market, value.name);
        this.pieChartLabels2.push([value.name]);
        this.pieChartData2.push(value.id);
        mybackgroundColor2.push(['#'+(0x1000000+(Math.random())*0xffffff).toString(16).substr(1,6)])
      })
    })
  )
  .subscribe((listingItem) => {
    console.log(listingItem) // gives an array of listingItem
  },
  error => console.log("oh no: " + error));

是否有正确的方法来返回禁止角色访问的状态?

It there a proper way to return a status for a forbidden role access?

问题是,如果我没有角色"Admin",我就不会进入方法GetTotalNumbers().因此,我无法返回自己的状态.因此Framework itslef返回403.我想将自己的Message作为错误传递.

Thr Problem is, i am not stepping into the Method GetTotalNumbers() if I have not the Role "Admin". Therefore i can't return my own status. So the Framework itslef is returning 403. I want to pass my own Message as an error.

推荐答案

我在您的问题下发表了评论.您应该注意发送给客户端的详细消息.在这种情况下,提供所需的角色不是很冒险. AuthorizationFailure.FailedRequirements 中包含您由于拒绝用户访问而拥有的所有内容.在这里,我向您介绍如何提取该内容,因为( IAuthorizationService 的默认 DefaultAuthorizationService )不会将其传递给管道.详细的管道始于 AuthorizeFilter (可以从 AuthorizeAttribute 转换):

As I commented under your question. You should be careful about the detailed message sent to the client. In this case, providing the required roles is not very risky. What you have for the reason of denying the user's access are contained in the AuthorizationFailure.FailedRequirements. Here I introduce to you how to extract that because the default DefaultAuthorizationService (of IAuthorizationService) does not pass that down to the pipeline. The detailed pipeline starts from AuthorizeFilter (which may be converted from AuthorizeAttribute):

AuthorizeFilter.OnAuthorizationAsync -> IPolicyEsyncaAuthorAuthor.>-> IAuthorizationService.AuthorizeAsync

因此您可以看到 IAuthorizationService.AuthorizeAsync 的结果已从 AuthorizationResult 转换为 PolicyAuthorizationResult ,该信息包含的信息要少得多(当然会丢失所有 Failure 详细信息).最后, PolicyAuthorizationResult 被转换为 ForbidResutl ChallengeResult .

So you can see that the result from IAuthorizationService.AuthorizeAsync is converted from AuthorizationResult to PolicyAuthorizationResult which contains much less info (of course losing all the Failure detail). Finally the PolicyAuthorizationResult is converted to just either ForbidResutl or ChallengeResult.

解决此问题的想法是通过继承 DefaultAuthorizationService 来创建自定义 IAuthorizationService ,并拦截对 AuthorizeAsync 的调用以捕获结果进入共享的内存中,例如通过 HttpContext.Features .请注意,您可以利用第三方拦截器框架(如 autofac )提供的DI拦截器.这里我们使用内置的DI框架,因此这是帮助拦截呼叫的最佳解决方案.

The idea to solve this problem is by creating your custom IAuthorizationService by inheriting from DefaultAuthorizationService and intercept the calls to AuthorizeAsync to capture the result into a shared in-memory, such as via the HttpContext.Features. Note that you can take some advantage of DI Interceptors which are available by third-party DI framework like autofac. Here we use the built-in DI framework so this is the best solution to help intercept the calls.

授权后,一旦您具有 AuthorizationResult 可用,就可以提取 Failure 并转换为一些友好的消息(注意不要暴露敏感信息)以发送给客户端

Once you have AuthorizationResult available after authorization, you can extract the Failure and convert to some friendly message (be careful to not expose sensitive info) to send to the client.

这是代码:

public class HttpAppAuthorizationService : DefaultAuthorizationService, IAuthorizationService
{
    readonly IHttpContextAccessor _httpContextAccessor;
    public HttpAppAuthorizationService(IAuthorizationPolicyProvider policyProvider, 
        IAuthorizationHandlerProvider handlers, 
        ILogger<DefaultAuthorizationService> logger, 
        IAuthorizationHandlerContextFactory contextFactory, 
        IAuthorizationEvaluator evaluator, 
        IOptions<AuthorizationOptions> options,
        IHttpContextAccessor httpContextAccessor) : base(policyProvider, handlers, logger, contextFactory, evaluator, options)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    async Task<AuthorizationResult> IAuthorizationService.AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements)
    {
        var result = await base.AuthorizeAsync(user, resource, requirements);
        //capture the result for later using
        _setAuthorizationResultFeature(result);
        return result;
    }
    async Task<AuthorizationResult> IAuthorizationService.AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName)
    {
        var result = await base.AuthorizeAsync(user, resource, policyName);
        //capture the result for later using
        _setAuthorizationResultFeature(result);
        return result;
    }
    void _setAuthorizationResultFeature(AuthorizationResult result)
    {
        var httpContext = _httpContextAccessor.HttpContext;
        if(httpContext != null)
        {
            httpContext.Features.Set<IAuthorizationResultFeature>(new AuthorizationResultFeature(result));
        }
    }
}

public interface IAuthorizationResultFeature
{
    AuthorizationResult AuthorizationResult { get; }
}
public class AuthorizationResultFeature : IAuthorizationResultFeature
{
    public AuthorizationResultFeature(AuthorizationResult result)
    {
        AuthorizationResult = result;
    }
    public AuthorizationResult AuthorizationResult { get; }
}

Startup.ConfigureServices 中注册您的自定义 IAuthorizationService :

services.AddSingleton<IAuthorizationService, HttpAppAuthorizationService>();

现在,在 IAsyncAlwaysRunResultFilter 的过滤器中,您可以提取 IAuthorizationResultFeature 以获得详细的故障并将其转换为所需的结果:

Now in a filter of IAsyncAlwaysRunResultFilter, you can extract the IAuthorizationResultFeature to get the detailed failure and convert it to the result you want:

public class CustomAsyncAlwaysRunResultFilterAttribute : Attribute, IAsyncAlwaysRunResultFilter
{
    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        var msg = "";
        var authorizationResult = context.HttpContext.Features.Get<IAuthorizationResultFeature>()?.AuthorizationResult;
        if(authorizationResult?.Failure != null ) {
            var rolesRequirements = authorizationResult.Failure.FailedRequirements.OfType<RolesAuthorizationRequirement>();
            msg = $@"You need to have all following roles (each group requires at least one role): 
                     {string.Join(", ", rolesRequirements.Select(e => $"({string.Join(", ", e.AllowedRoles)})"))}";
            //sends back a plain text result containing the msg
            //this can be obtained by the client
            context.Result = new ContentResult { Content = msg, StatusCode = 403 };
        }            
        await next();            
    }
}

实际上,您也可以将其他类型的 AuthorizationRequirement 纳入格式化邮件的过程中.上面的代码只是仅格式化 RolesAuthorizationRequirement (在这里适合您的具体情况)的示例.

Actually you can take other kinds of AuthorizationRequirement into the process of formatting the message as well. The code above is just an example to format only the RolesAuthorizationRequirement (which suits your specific case here).

IAsyncAlwaysRunResultFilter 应该全局注册(就像其他类型的过滤器一样).希望您知道该怎么做(使用Google搜索一定可以为您提供快速的结果).

The IAsyncAlwaysRunResultFilter should be registered globally (in the way just like other kinds of filter). I hope you know how to do that (googling will surely provide you a quick result).

这篇关于在哪里返回403禁止状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆