为什么需要设置DefaultForbidScheme

时间:2019-02-07 16:54:06

标签: asp.net-core .net-core

在WebAPI .net核心项目中,我创建了一个中间件类来验证api密钥。通过对其进行验证,它会检索密钥在invoke方法内(用户或admin)具有的权限。

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

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;
                    }

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

验证经过身份验证的api密钥的作用

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

的错误
  

没有DefaultForbidScheme

我到处搜索并通过客户计划将身份验证添加到我的startup.cs中

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

并创建了 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;
        }
    }

现在,如果该原理没有Admin,则它将失败而没有错误,但是API返回的响应为200,没有任何内容。我期待4xx响应,并显示消息“身份验证失败”

我只是试图弄清为什么它看起来不像预期的那样“固定”,所以我不明白它是如何固定的。

我应该有更好的方法吗?

问候 标记

1 个答案:

答案 0 :(得分:1)

  

为什么它看起来不像预期的那样“固定”,所以我不明白它是如何固定的。

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

StatusCode=403

请注意,您不必返回public async Task ForbidAsync(AuthenticationProperties properties) { properties = properties ?? new AuthenticationProperties(); _context.Response.StatusCode = 403; // ... return Task.CompletedTask; } ,因为它并不关心结果。

  

我应该有更好的方法吗?

ASP.NET核心团队为我们提供了一个抽象类Task.FromResult()来处理身份验证。此抽象类具有ForbidAsync(AuthenticationProperties properties)(以及其他公共方法)的内置实现。因此,如下扩展该抽象类非常容易:

AuthenticationHandler

最后,添加身份验证服务的配置:

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();
    }
}

它应该可以正常工作。