为什么我需要设置一个 DefaultForbidScheme

mar*_*777 6 .net-core asp.net-core

在 WebAPI .net 核心项目中,我创建了一个验证 api 密钥的中间件类。通过验证它,它检索密钥在 invoke 方法中拥有的权限(用户或管理员)。

我通过一个开关来设置原理

GenericIdentity identity = new GenericIdentity("API");
GenericPrincipal principle = null;

          //we have a valid api key, so set the role permissions of the key
          switch (keyValidatorRes.Role)
           {
               case Roles.User:
                    principle = new GenericPrincipal(identity, new[] { "User" });  
                    context.User = principle;
                    break;
                case Roles.Admin:
                    principle = new GenericPrincipal(identity, new[] { "Admin" });         
                    context.User = principle;
                    break;
                default:
                    principle = new GenericPrincipal(identity, new[] { "Other" });
                    context.User = principle;
                    break;
                    }
Run Code Online (Sandbox Code Playgroud)

在控制器方法上我有
[Authorize(Roles = "Admin")]

验证经过身份验证的 api 密钥的角色

如果用户有 admin 原则,它会按预期进行。但是,如果它有用户或其他原则,那么我会收到关于

没有 DefaultForbidScheme

我搜索了一下,并使用客户方案在我的 startup.cs 中添加了身份验证

services.AddAuthentication(options=> {
       options.DefaultForbidScheme = "forbidScheme";
       options.AddScheme<AuthSchemeHandle>("forbidScheme", "Handle Forbidden");
});
Run Code Online (Sandbox Code Playgroud)

并创建了AuthSchemeHandle

public class AuthSchemeHandle : IAuthenticationHandler
    {
        private HttpContext _context;

        public Task<AuthenticateResult> AuthenticateAsync()
        {
            return Task.FromResult(AuthenticateResult.NoResult());
        }

        public Task ChallengeAsync(AuthenticationProperties properties)
        {
            throw new NotImplementedException();
        }

        public Task ForbidAsync(AuthenticationProperties properties)
        {
            return Task.FromResult(AuthenticateResult.Fail("Failed Auth"));
        }

        public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
        {
            _context = context;
            return Task.CompletedTask;
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在,如果原则没有 Admin,它会失败而不会出现错误,但 API 上返回的响应200没有内容。我期待收到4xx消息“身份验证失败”的回复

我只是想弄清楚为什么它不像预期的那样虽然看起来“固定”,但我不明白它是如何修复它的。

有没有更好的方法让我应该这样做?

问候马克

itm*_*nus 11

为什么它不像预期的那样虽然看起来“固定”我不明白它是如何修复它的。

身份验证处理程序调用IAuthenticationHandler.ForbidAsync()方法时没有黑魔法。我们必须自己做相关的事情。简而言之,StatusCode=403根据您的需要设置。

public async Task ForbidAsync(AuthenticationProperties properties)
{
    properties = properties ?? new AuthenticationProperties();
    _context.Response.StatusCode = 403;
    // ...
    return Task.CompletedTask;    
}
Run Code Online (Sandbox Code Playgroud)

作为旁注,您不需要 return aTask.FromResult()因为它不关心结果。

有没有更好的方法让我应该这样做?

ASP.NET Core 团队为我们提供了一个抽象类AuthenticationHandler来处理身份验证。这个抽象类具有ForbidAsync(AuthenticationProperties properties)(以及其他公共方法)的内置实现。所以扩展这个抽象类很容易,如下所示:

public class MyAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    public MyAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) 
        : base(options, logger, encoder, clock)
    {
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        return AuthenticateResult.NoResult();
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,为认证服务添加一个配置:

services
    .AddAuthentication(options=>{
        options.DefaultAuthenticateScheme = "forbidScheme";
        options.DefaultForbidScheme = "forbidScheme";
        options.AddScheme<MyAuthenticationHandler>("forbidScheme", "Handle Forbidden");
    });
Run Code Online (Sandbox Code Playgroud)

它应该按预期工作。