【问题标题】:Why do I need to set a DefaultForbidScheme为什么我需要设置 DefaultForbidScheme
【发布时间】:2019-02-07 16:54:06
【问题描述】:

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

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

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

现在,如果原则没有管理员,它会失败而没有错误,但在 API 上返回的响应是 200,没有内容。我期待 4xx 回复消息“验证失败”

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

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

问候 标记

【问题讨论】:

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


    【解决方案1】:

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

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

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

    附带说明,您不需要返回 Task.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();
        }
    }
    

    最后,添加认证服务的配置:

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

    它应该按预期工作。

    【讨论】:

    • 感谢 itminus,按说明工作。因此,根据您所说的,我本可以保留它的方式,而我所要做的就是在响应中设置响应状态代码。不过我已经把它改成了抽象类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多