[英]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.在这里,我向您介绍如何提取它,因为默认DefaultAuthorizationService
( IAuthorizationService
)不会将其传递给管道。 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
被转换为ForbidResutl
或ChallengeResult
。
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.