【问题标题】:No authenticationScheme was specified, and there was no DefaultForbidScheme found with custom policy based authorization没有指定 authenticationScheme,并且没有找到具有基于自定义策略的授权的 DefaultForbidScheme
【发布时间】:2018-12-11 01:48:37
【问题描述】:

我有一个基于自定义策略的授权处理程序,定义如下。在用户点击此应用程序之前处理身份验证,因此我只需要授权。我收到错误:

没有指定 authenticationScheme,也没有 DefaultForbidScheme。

如果授权检查成功,那么我没有收到错误,一切都很好。此错误仅在授权检查失败时发生。我希望在失败时返回 401。

public class EasRequirement : IAuthorizationRequirement
{
    public EasRequirement(string easBaseAddress, string applicationName, bool bypassAuthorization)
    {
        _client = GetConfiguredClient(easBaseAddress);
        _applicationName = applicationName;
        _bypassAuthorization = bypassAuthorization;
    }

    public async Task<bool> IsAuthorized(ActionContext actionContext)
    {
        ...
    }
}
public class EasHandler : AuthorizationHandler<EasRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, EasRequirement requirement)
    {
        var mvcContext = context.Resource as ActionContext;

        bool isAuthorized;

        try
        {
            isAuthorized = requirement.IsAuthorized(mvcContext).Result;
        }
        catch (Exception)
        {
            // TODO: log the error?
            isAuthorized = false;
        }

        if (isAuthorized)
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }

        context.Fail();
        return Task.FromResult(0);
    }
}
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        var easBaseAddress = Configuration.GetSection("EasBaseAddress").Value;
        var applicationName = Configuration.GetSection("ApplicationName").Value;
        var bypassAuthorization = bool.Parse(Configuration.GetSection("BypassEasAuthorization").Value);

        var policy = new AuthorizationPolicyBuilder()
            .AddRequirements(new EasRequirement(easBaseAddress, applicationName, bypassAuthorization))
            .Build();

        services.AddAuthorization(options =>
        {
            options.AddPolicy("EAS", policy);
        });

        services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        services.AddSingleton<IAuthorizationHandler, EasHandler>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseAuthentication();

        app.UseMvc();
    }
}

【问题讨论】:

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


    【解决方案1】:

    授权和身份验证在 ASP.NET Core 中密切相关。当授权失败时,这将被传递给一个身份验证处理程序来处理授权失败。

    因此,即使您不需要实际的身份验证来识别您的用户,您仍然需要设置一些能够处理禁止和质询结果(403 和 401)的身份验证方案。

    为此,您需要调用AddAuthentication() 并配置默认的禁止/挑战方案:

    services.AddAuthentication(options =>
    {
        options.DefaultChallengeScheme = "scheme name";
    
        // you can also skip this to make the challenge scheme handle the forbid as well
        options.DefaultForbidScheme = "scheme name";
    
        // of course you also need to register that scheme, e.g. using
        options.AddScheme<MySchemeHandler>("scheme name", "scheme display name");
    });
    

    MySchemeHandler 需要实现IAuthenticationHandler,在您的情况下,您尤其需要实现ChallengeAsyncForbidAsync

    public class MySchemeHandler : IAuthenticationHandler
    {
        private HttpContext _context;
    
        public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
        {
            _context = context;
            return Task.CompletedTask;
        }
    
        public Task<AuthenticateResult> AuthenticateAsync()
            => Task.FromResult(AuthenticateResult.NoResult());
    
        public Task ChallengeAsync(AuthenticationProperties properties)
        {
            // do something
        }
    
        public Task ForbidAsync(AuthenticationProperties properties)
        {
            // do something
        }
    }
    

    【讨论】:

    • 有没有办法防止您描述的默认行为? " 当授权失败时,这将被传递给一个身份验证处理程序来处理授权失败"
    • @ChristophAdamakis 不,这就是身份验证和授权的链接方式。当授权失败时,身份验证方案必须处理该失败。 – 你想在那里做什么?必须发生一些事情。
    • @ajamrozek 浏览器弹出窗口中要求您登录的凭据提示?或者只是重定向到一些登录表单?前者不应该是可能的,而后者是通过拥有自己的身份验证方案来明确阻止的。也许你应该提出一个新问题,涵盖你到底在做什么。请随时在此处发布问题的链接,我会看看。
    • “应该不可能”。接受挑战;)原来我有一些遗留的东西在launchsettings.json中启用了WindowsAuth。把它拿出来,就没有更多的提示了。否则,这个答案对我的指导非常好。
    • 如果有人想知道“做某事”应该是什么样子,请参考stackoverflow.com/a/54587054/106688
    【解决方案2】:

    对于 IIS/IIS Express,只需在接受的答案中添加这一行而不是上述所有内容即可获得您期望的适当 403 响应;

     services.AddAuthentication(IISDefaults.AuthenticationScheme);
    

    【讨论】:

    • 奇怪:我有这条线,但在生产服务器上仍然收到 No authenticationScheme was specified, and there was no DefaultForbidScheme found. 错误。
    • 我也接到了services.AddAuthentication(IISDefaults.Ntlm);的以下电话。现在将删除它,看看这是否会导致错误消息。
    • 不,也没有帮助。
    猜你喜欢
    • 2018-04-29
    • 2019-11-02
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 2021-10-18
    • 2021-05-24
    • 2019-03-22
    • 1970-01-01
    相关资源
    最近更新 更多