ABP点滴:API无权访问资源时,返回 PolicyName 信息

发布时间 2023-06-18 19:58:56作者: 无常

ABP无权访问API时,返回的是403 Forbidden 和重定向 Localtion ,但不知道具体是哪个Policy受阻。
整改思路:

  1. 重写 MethodInvocationAuthorizationService, 抛出AbpAuthorizationException异常时附带 PolicyName
  2. 重写 DefaultAbpAuthorizationExceptionHandler ,在http响应头中增加上无权限的 PolicyName。
  3. 前端判断返回403再从headers中获取

效果如:

image

相关源码:


[ExposeServices(typeof(IAbpAuthorizationExceptionHandler))]
[Dependency(ReplaceServices = true)]
public class Ch2AuthorizationExceptionHandler : DefaultAbpAuthorizationExceptionHandler
{
    public Ch2AuthorizationExceptionHandler()
    {
    }

    public override Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext)
    {
        if (exception.Data.Contains("PolicyName"))
        {
            var policyName = (string)exception.Data["PolicyName"]!;
            httpContext.Response.Headers.Add("X-Policy-Name", new Microsoft.Extensions.Primitives.StringValues(policyName));
        }

        return base.HandleAsync(exception, httpContext);
    }
}



[ExposeServices(typeof(IMethodInvocationAuthorizationService))]
[Volo.Abp.DependencyInjection.Dependency(ReplaceServices = true)]
public class Ch2MethodInvocationAuthorizationService : IMethodInvocationAuthorizationService, ITransientDependency
{
    private readonly IAbpAuthorizationPolicyProvider _abpAuthorizationPolicyProvider;
    private readonly IAbpAuthorizationService _abpAuthorizationService;

    public Ch2MethodInvocationAuthorizationService(
        IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider,
        IAbpAuthorizationService abpAuthorizationService)
    {
        _abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider;
        _abpAuthorizationService = abpAuthorizationService;
    }

    public async Task CheckAsync(MethodInvocationAuthorizationContext context)
    {
        if (AllowAnonymous(context))
        {
            return;
        }

        var authorizationPolicy = await AuthorizationPolicy.CombineAsync(
            _abpAuthorizationPolicyProvider,
            GetAuthorizationDataAttributes(context.Method)
        );

        if (authorizationPolicy == null)
        {
            return;
        }

        //改动这里
        //await _abpAuthorizationService.CheckAsync(authorizationPolicy);
        if (!await _abpAuthorizationService.IsGrantedAsync(authorizationPolicy))
        {
            var policys = authorizationPolicy.Requirements.Cast<PermissionRequirement>()
                .Select(o => o.PermissionName).JoinAsString(",");
            throw new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenPolicyHasNotGranted)
                .WithData("PolicyName", policys);
        }
    }

    protected virtual bool AllowAnonymous(MethodInvocationAuthorizationContext context)
    {
        return context.Method.GetCustomAttributes(true).OfType<IAllowAnonymous>().Any();
    }

    protected virtual IEnumerable<IAuthorizeData> GetAuthorizationDataAttributes(MethodInfo methodInfo)
    {
        var attributes = methodInfo
            .GetCustomAttributes(true)
            .OfType<IAuthorizeData>();

        if (methodInfo.IsPublic && methodInfo.DeclaringType != null)
        {
            attributes = attributes
                .Union(
                    methodInfo.DeclaringType
                        .GetCustomAttributes(true)
                        .OfType<IAuthorizeData>()
                );
        }

        return attributes;
    }
}