提问人:LFN 提问时间:1/23/2017 最后编辑:P. MagnussonLFN 更新时间:1/31/2023 访问量:4091
为什么 AuthenticationHandler.HandleForbiddenAsync 完全忽略运行的代码?
Why does AuthenticationHandler.HandleForbiddenAsync Totally Ignore Code That Runs?
问:
谢谢你们抽出时间。 此实现有意不使用内置 Cookie、JWT 令牌或任何其他身份验证机制。请不要建议使用任何内置的 Auth 内容来绕过该问题。这是关于一个完全定制的身份验证/授权实现,用于诊断和了解正在发生的事情以及原因。这里的关键词是理解。
public class CustomAuthenticationHandler : AuthenticationHandler<CustomAuthenticationOptions> {
protected override Task<AuthenticateResult> HandleAuthenticateAsync() {
// Do stuff and return appropriately after choosing to set the
// authenticated principle or not.
}
protected override Task<bool> HandleUnauthorizedAsync(ChallengeContext context) {
// This method name suggests that you can choose what happens in the event
// that Authentication fails. Common sense suggests we should expect a 401
// which we do see - but something in the internals ignores anything we
// do here - instead returning a blank page with a 401 result.
// Note that the event ALWAYS fires and code ALWAYS runs without errors when
// Authentication fails but the code is entirely ignored (so our redirect
// doesnt happen).
// Adding a specific "ActiveAuthenticationSchemes" proerty to the Controller Action gets the redirect to be honoured.
// Why offer this override (or even invoke the event) if it will be totally ignored by default???
// Why REQUIRE that every Authorization attribute must specify an ActiveAuthenticationSchemes
// property when there is only 1 scheme running? Its madness for large complex applications.
// This will be ignored by default
Context.Response.StatusCode = (int)HttpStatusCode.Redirect;
Context.Response.Redirect("/login?returnUrl=" + Options.UrlEncoder.Encode(httpRequest.Path + httpRequest.QueryString));
// Return true to stop internals overriding our code? Nope - still ignored.
return Task.FromResult(true);
}
protected override Task<bool> HandleForbiddenAsync(ChallengeContext context) {
// This method name suggests that you can choose what happens in the event
// that Authentication succeeds and Authorisation fails. We expect to see
// a 403 Forbidden here. But again what we see is a blank page and a 401 Unathorized.
// Something in the internals is ignoring this code and CHANGING what would
// have been a sensible 403 result into a 401.
// Like the HandleUnauthorizedAsync method, it is possible to get this
// method code to be honoured if we explicitly set an ActiveAuthenticationSchemes
// property on every Authorize attribute.
// Isnt this again a bonkers requirement for complex applications?
// This will be ignored in favour of a blank page and a 401
// We can set either the StatusCode or do the redirect, both will be duly ignored
Context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
Context.Response.Redirect("/_403");
// Return true to stop internals overriding our code? Nope - still ignored.
return Task.FromResult(true);
}
}
为了完整起见,启动如下所示:
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
services.AddDataProtection();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
app.UseCustomAuthenticationMiddleware(
new CustomAuthenticationOptions() {
//AuthenticationScheme = "CustomAuthenticationScheme",
AutomaticAuthenticate = true,
AutomaticChallenge = true
}
);
// -----
app.UseMvc(routes => {
routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
我们的中间件有一个简单的实现,它调用处理程序:
protected override AuthenticationHandler<CustomAuthenticationOptions> CreateHandler() {
return new CustomAuthenticationHandler();
}
那么,是否有某种内置的内部故障保护来阻止人们在不对每个操作的每个 Authorize 属性显式设置 ActiveAuthenticationSchemes 的情况下连接自定义身份验证(以阻止我们这样做)?
我很困惑代码运行没有错误,但随后被忽略了。
关于如何自己诊断的建议和解释一样受欢迎 - 这让我发疯:) !!!
* 编辑/更新
可能的线索。似乎 [Authorize] 属性也有一些令人愤怒的奇怪行为。在操作级别应用“ActiveAuthenticationSchemes”时,对于“未经授权”和“禁止”的结果,事情开始如你所期望的那样工作。但是,将该属性移动到控制器级别,它仅对“未经授权”有效。禁止的处理程序代码再次被忽略(导致空白页和 401 而不是编码的重定向)。这里的内部有些东西正在踩踏明智的甚至编码的结果。不是吗?:) ...查看 MVC 源代码,看起来 MVC 可能会强制执行 401 而不是质询结果。我希望这不是真的......
* 编辑 2
看来,至少在一定程度上,这是真的。我创建了一个仅运行 MVC 的新项目(没有额外的身份验证或授权),并且无论您是否经过身份验证,MVC 都会返回 401 Unauthorized。感觉这应该是 403 禁止的,如果授权但权限不足。显然,身份验证和 MVC 之间没有连接某些东西,导致代码被忽略,行为被 MVC 401 结果覆盖。或。。。仍在调查中...
答:
若要解决此问题,请改用 HandleChallengeAsync 方法:
protected override Task HandleChallengeAsync(AuthenticationProperties properties) { string redirectURL; if (ReadConfig.LoginURL_Exists && Request.AcceptHTML ()) { redirectURL = TextHelper.AppendVarValueToHTTPURL (ReadConfig.LoginURL, GeneralConstants.RETURN_URL, Request.GetDisplayUrl()); Response.Redirect (redirectURL); return Task.CompletedTask; } Response.StatusCode = (int) HttpStatusCode.Unauthorized; return Task.CompletedTask; }
评论
.UseIdentity(...)
Configure
options.AddPolicy("", builder => builder.RequireAuthenticatedUser());