Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在哪里返回403禁止状态?_C#_Angular_Asp.net Core - Fatal编程技术网

C# 在哪里返回403禁止状态?

C# 在哪里返回403禁止状态?,c#,angular,asp.net-core,C#,Angular,Asp.net Core,我正在使用授权路由获取数据,但由于该路由被禁止,因此我无法返回错误 [Route("getTotal")] [HttpGet] [Authorize(Roles = "Admin")] public IActionResult GetTotalNumbers() { var test = User.Claims; try { var logic = new DrainlockLogic(_appSettings);

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

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


问题是,如果我没有“Admin”角色,我就不会使用getTotalNumber()方法。因此,我不能返回我自己的状态。因此框架itslef返回403。我想将我自己的消息作为错误传递。

调试代码并跟踪所有步骤。确保代码抛出错误

[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);
    }
}
代码可能不会抛出错误

你确定这是抛出错误吗

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

我猜方法GetTolalNumbers返回null而不是抛出错误。

正如我在您的问题下所评论的那样。您应该注意发送给客户机的详细消息。在这种情况下,提供所需的角色不是很危险。 您因拒绝用户访问而拥有的信息包含在
授权失败.FailedRequirements
中。这里我向您介绍如何提取它,因为默认的
DefaultAuthorizationService
(属于
IAuthorizationService
)不会将其传递给管道。详细管道从
AuthorizeFilter
开始(可从
AuthorizeAttribute
转换):

->->

因此,您可以看到,
iaauthorizationservice.authorizationasync
的结果从
AuthorizationResult
转换为
PolicyAuthorizationResult
,其中包含的信息要少得多(当然会丢失所有
故障
详细信息)。最后,
PolicyAuthorizationResult
转换为
banforresultl
ChallengeResult

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

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

代码如下:

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; }
}
现在,在
iasyncalwaysrunsultfilter
的过滤器中,您可以提取
iaauthorizationresultfeature
以获取详细故障并将其转换为所需的结果:

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();            
    }
}
public类customAsyncAlwaysRunsultFilterAttribute:属性,IAsyncalwaysRunsultFilter
{
ResultExecutionAsync上的公共异步任务(ResultExecutionContext,ResultExecutionDelegate next)
{
var msg=“”;
var authorizationResult=context.HttpContext.Features.Get()?.authorizationResult;
if(授权结果?.Failure!=null){
var rolesRequirements=authorizationResult.Failure.FailedRequirements.OfType();
msg=$@“您需要具有以下所有角色(每个组至少需要一个角色):
{string.Join(“,”,rolesRequirements.Select(e=>$”({string.Join(“,”,e.AllowedRoles)})”)}”;
//发回包含消息的纯文本结果
//这可由客户获得
context.Result=newcontentresult{Content=msg,StatusCode=403};
}            
等待下一个();
}
}
实际上,您也可以在格式化消息的过程中使用其他类型的
授权要求。上面的代码只是一个仅格式化
RolesAuthorizationRequirement
的示例(适合您的具体情况)


iasyncalwaysrunsultfilter
应该全局注册(与其他类型的过滤器一样)。我希望您知道如何做到这一点(谷歌搜索肯定会为您提供一个快速的结果)。

如果您正确地应用了
403
,框架将返回该
。您也可以通过返回
return bankeen(),手动将其返回-你到底想要什么?没错,我得到了403的框架。但是我想传递我自己的消息,如果我的角色不正确,这是不可能的。看起来您想提供有关用户被拒绝访问的详细信息。我认为这样做不是一个好的做法。详细信息可能是一个安全问题。在这种情况下,一般的信息要好得多。这就像当登录失败时,我们没有清楚地提供关于用户不存在或密码不正确的消息,我们只是返回一条消息,说类似“未成功”。这也很难实现,当前的授权管道需要许多AuthorizationHandler进行授权,我相信结果中没有提供具体的原因。看起来它未经授权的原因可以从失败需求列表中提取出来,该列表包含在
AuthorizationFailure.FailedRequests
(在使用授权中间件时)。但是,正如我所说,在向客户提供更详细的信息时,您应该小心。我认为这就是解决方案。谢谢。很抱歉我的解释不好。如果我没有“管理员”角色我不能返回任何东西,因为我没有进入方法本身。我从框架中得到403,但我想传递我自己的消息