如何从自定义AuthorizeAttribute返回自定义消息?

时间:2020-05-21 12:59:59

标签: c# asp.net-core authorization auth0

我正在使用带有Auth0的ASP.NET Core 3.1 WebAPI。

我想实现一个自定义的AuthorizeAttribute,它将执行简单的权限检查,如果缺少权限,则返回403并显示一条消息。

代码如下:

Startup.cs(ConfigureServices)

services
        .AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }
        )
        .AddJwtBearer(options =>
            {
                var keyResolver = new MultipleIssuerSigningKeyResolver();
                options.MetadataAddress = "https://.../.well-known/openid-configuration";
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidAudience = Auth0Configuration.Audience,
                    ValidIssuers = Auth0Configuration.Issuers,
                    IssuerSigningKeyResolver = (token, securityToken, kid, parameters) =>
                        keyResolver.GetSigningKey(securityToken.Issuer, kid)
                };
            }
        );

自定义AuthorizeAttribute

public class AuthorizeAttribute : Microsoft.AspNetCore.Authorization.AuthorizeAttribute, IAsyncAuthorizationFilter
{
    private readonly string[] _permissions;

    public AuthorizeAttribute(params string[] permissions)
    {
        _permissions = permissions;
    }

    /// <inheritdoc />
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        var user = (IRemoteUser) context.HttpContext.RequestServices.GetService(typeof(IRemoteUser));
        await user.Fetch(context.HttpContext);
        context.HttpContext.Items["RemoteUser"] = user;
        foreach (var permission in _permissions)
        {
            if (user.HasPermission(permission)) continue;

            // Permission not found, return forbidden.
            context.Result = new ForbidResult($"Permission '{permission}' is required.");
            return;
        }
    }
}

我这样称呼它:

[Authorize("support:all")]
[HttpPost]
public async Task<ActionResult> Create([FromBody] SupportMessageCreateDto dto)
{...}

如果我不向new ForbidResult()提供消息,则效果很好。如果缺少权限,我会收到403。但是,如果我提供此消息,则会得到:

{
  "error": "No authentication handler is registered for the scheme 'Permission 'support:all' is required.'. The registered schemes are: Bearer. Did you forget to call AddAuthentication().Add[SomeAuthHandler](\"Permission 'support:all' is required.\",...)?"
}

为什么会这样,我该如何解决?我真的很喜欢此设置,因为它很简单,但是此消息是必需的。

1 个答案:

答案 0 :(得分:1)

我对结果类型犯了一个错误。 ForbidResult实际上期望身份验证方案为构造函数中的字符串。我替换了

context.Result = new ForbidResult($"Permission '{permission}' is required.");

context.Result = new ObjectResult($"Permission '{permission}' is required.")
{
    StatusCode = (int) HttpStatusCode.Forbidden
};

它现在可以工作。