简体   繁体   English

在哪里返回 403 禁止状态?

[英]Where to return 403 Forbidden Status?

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

My error is always null.我的错误总是 null。

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?是否有适当的方法来返回禁止角色访问的状态?

Thr Problem is, i am not stepping into the Method GetTotalNumbers() if I have not the Role "Admin".问题是,如果我没有角色“管理员”,我就不会进入方法 GetTotalNumbers()。 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.所以框架本身返回 403。我想将我自己的消息作为错误传递。

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 .您拒绝用户访问的原因包含在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.在这里,我向您介绍如何提取它,因为默认DefaultAuthorizationServiceIAuthorizationService )不会将其传递给管道。 The detailed pipeline starts from AuthorizeFilter (which may be converted from AuthorizeAttribute ):详细的管道从AuthorizeFilter开始(可以从AuthorizeAttribute转换):

AuthorizeFilter.OnAuthorizationAsync -> IPolicyEvaluator.AuthorizeAsync -> IAuthorizationService.AuthorizeAsync AuthorizeFilter.OnAuthorizationAsync -> IPolicyEvaluator.AuthorizeAsync -> IAuthorizationService.AuthorizeAsync

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).因此,您可以看到IAuthorizationService.AuthorizeAsync的结果从AuthorizationResult转换为PolicyAuthorizationResult包含的信息要少得多(当然会丢失所有Failure细节)。 Finally the PolicyAuthorizationResult is converted to just either ForbidResutl or ChallengeResult .最后PolicyAuthorizationResult被转换为ForbidResutlChallengeResult

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 .解决此问题的想法是通过从DefaultAuthorizationService继承来创建自定义IAuthorizationService并拦截对AuthorizeAsync的调用以将结果捕获到共享的内存中,例如通过HttpContext.Features Note that you can take some advantage of DI Interceptors which are available by third-party DI framework like autofac .请注意,您可以利用第三方 DI 框架(如autofac )提供的 DI 拦截器。 Here we use the built-in DI framework so this is the best solution to help intercept the calls.这里我们使用内置的 DI 框架,因此这是帮助拦截调用的最佳解决方案。

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.一旦授权后AuthorizationResult可用,您可以提取Failure并转换为一些友好的消息(注意不要暴露敏感信息)发送给客户端。

Here's the code:这是代码:

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

Register your custom IAuthorizationService in Startup.ConfigureServices :Startup.ConfigureServices中注册您的自定义IAuthorizationService

services.AddSingleton<IAuthorizationService, HttpAppAuthorizationService>();

Now in a filter of IAsyncAlwaysRunResultFilter , you can extract the IAuthorizationResultFeature to get the detailed failure and convert it to the result you want:现在在IAsyncAlwaysRunResultFilter的过滤器中,您可以提取IAuthorizationResultFeature以获取详细的失败并将其转换为您想要的结果:

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

Actually you can take other kinds of AuthorizationRequirement into the process of formatting the message as well.实际上,您也可以在格式化消息的过程中使用其他类型的AuthorizationRequirement The code above is just an example to format only the RolesAuthorizationRequirement (which suits your specific case here).上面的代码只是一个仅格式化RolesAuthorizationRequirement的示例(此处适合您的特定情况)。

The IAsyncAlwaysRunResultFilter should be registered globally (in the way just like other kinds of filter). IAsyncAlwaysRunResultFilter应该全局注册(就像其他类型的过滤器一样)。 I hope you know how to do that (googling will surely provide you a quick result).我希望您知道如何做到这一点(谷歌搜索肯定会为您提供快速的结果)。

Debug your code and trace all steps.调试您的代码并跟踪所有步骤。 Make sure the code throws error.确保代码抛出错误。

Probably, the code does not throw error.可能代码不会引发错误。

Are you sure this is throwing error?你确定这是抛出错误吗?

var logic = new DrainlockLogic(_appSettings);
var ret = logic.GetTotalNumbers();  
return Ok(ret);

I guess the method GetTolalNumbers returns null instead of throwing error.我猜 GetTolalNumbers 方法返回 null 而不是抛出错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从禁止返回403的网站解析 - parsing from website which return 403 forbidden 禁止代理返回错误403-C# - Proxy return error 403 forbidden - c# 无法从 Jenkins 有问题地获取最后构建状态 - 403 禁止 - Cant get Last build status problematically from Jenkins - 403 forbidden 如何使用Forbidden状态web api返回ModelState - How to return ModelState with Forbidden status web api 如何在apicontroller操作上返回403状态代码 - how to return a 403 status code on apicontroller action HttpWebResponse return远程服务器返回错误:(403)禁止 - HttpWebResponse return The remote server returned an error: (403) Forbidden Web API 应该返回 403 Forbidden 还是根本没有端点? - Should Web API return 403 Forbidden or not have an endpoint at all? 为什么 HomeGraph API 上的请求同步返回 403 Forbidden? - Why does Request Sync on HomeGraph API return 403 Forbidden? 授权策略总是返回 403 (Forbidden) - MVC/API - Authorize Policy always return 403 (Forbidden) - MVC/API IdentityServer4 总是返回 401 Unauthorized 或 403 Forbidden - IdentityServer4 always return 401 Unauthorized or 403 Forbidden
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM