【发布时间】:2017-01-23 12:25:09
【问题描述】:
感谢您的宝贵时间。 此实现有意不使用内置 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();
}
那么,是否有某种内置的内部故障保险可以阻止人们连接自定义身份验证,而无需在每个 Action 的每个 Authorize 属性上显式设置 ActiveAuthenticationSchemes(阻止我们这样做)?
我很困惑代码运行时没有错误但随后被忽略。
关于如何自己诊断这个问题的建议和解释一样受欢迎 - 这让我发疯:) !!!
* 编辑/更新
可能的线索。似乎 [Authorize] 属性也有一些令人发指的奇怪行为。当在 Action 级别应用“ActiveAuthenticationSchemes”时,事情开始按您对 Unauthorized 和 Forbidden 结果的预期工作。不过,将该属性移至控制器级别,它仅对未授权有效。被禁止的处理程序代码再次被忽略(导致空白页和 401 而不是编码重定向)。这里内部的某些东西正在践踏合理甚至编码的结果。不是吗? :) ...查看 MVC 源代码,看起来 MVC 可能会强制执行 401 而不是质询结果。我希望那不是真的……
* 编辑 2
这似乎是,至少部分是真的。我创建了一个只运行 MVC 的新项目(没有额外的身份验证或授权),并且无论您是否经过身份验证,MVC 都会返回 401 Unauthorized。感觉这应该是 403 Forbidden if Authorized 但权限不足。很明显,身份验证和 MVC 之间没有连接,导致代码被忽略并且行为被 MVC 401 结果覆盖。也许……还在调查……
【问题讨论】:
-
我认为这是因为您在某处有一个授权中间件,它可以捕获并处理它,如果您的
.UseIdentity(...)方法中有.UseIdentity(...),则可能是 Identity。您是否也使用完全相同的授权方案? -
我没有使用身份、Cookie、令牌或任何其他类型的内置身份验证或授权工具。我故意试图理解似乎有点奇怪的默认行为。我正在使用 MVC,所以也许这可能会返回 401 而不是挑战结果或其他什么?
-
您是否有其他已注册的政策,例如
options.AddPolicy("", builder => builder.RequireAuthenticatedUser());? -
不,没有政策 - 所有代码都已发布。看起来可能是 MVC 我会更新帖子。
标签: asp.net-core authorization