ASP.NET Core 2.0禁用自动挑战
将ASP.NET Core项目升级到2.0后,尝试访问受保护的端点不再返回401,而是重定向到(不存在的)端点以尝试让用户进行身份validation。
所需的行为是应用程序只是返回401.以前我会在配置身份validation时设置AutomaticChallenge = false
,但根据这篇文章 ,设置不再相关(实际上它不再存在)。
我的身份validation配置如下:
Startup.cs.ConfigureServices():
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(o => { o.Cookie.Name = options.CookieName; o.Cookie.Domain = options.CookieDomain; o.SlidingExpiration = true; o.ExpireTimeSpan = options.CookieLifetime; o.TicketDataFormat = ticketFormat; o.CookieManager = new CustomChunkingCookieManager(); });
配置():
app.UseAuthentication();
如何禁用自动质询,以便在用户未通过身份validation时应用程序返回401?
经过一些研究,我发现我们可以通过以下方法处理这个问题:
我们可以添加Identity和JWT两种身份validation方案; 并使用Identity方案进行身份validation并使用JWT模式进行质询,JWT在挑战时不会重定向到任何登录路由。
services.AddIdentity().AddEntityFrameworkStores(); services.AddAuthentication((cfg => { cfg.DefaultScheme = IdentityConstants.ApplicationScheme; cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; })).AddJwtBearer();
正如其他一些答案所指出的那样,不再有使用cookie身份validation关闭自动质询的设置。 解决方案是覆盖OnRedirectToLogin
:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.Events.OnRedirectToLogin = context => { context.Response.Headers["Location"] = context.RedirectUri; context.Response.StatusCode = 401; return Task.CompletedTask; }; });
这可能会在未来发生变化: https : //github.com/aspnet/Security/issues/1394
根据这篇文章:
在1.x中, AutomaticAuthenticate和AutomaticChallenge属性旨在在单个身份validation方案上设置。 没有好办法强制执行此操作。
在2.0中,这两个属性已作为单个AuthenticationOptions实例上的标志删除,并已移至基本AuthenticationOptions类中。 可以在Startup.cs的ConfigureServices方法中的AddAuthentication方法调用中配置属性
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
或者,使用AddAuthentication方法的重载版本来设置多个属性。 在以下重载方法示例中,默认方案设置为CookieAuthenticationDefaults.AuthenticationScheme。 或者,可以在您的[授权]属性或授权策略中指定身份validation方案。
services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; });
如果满足下列条件之一,则在2.0中定义默认方案:
- 您希望用户自动登录
- 您可以使用[授权]属性或授权策略,而无需指定方案
此规则的一个例外是AddIdentity方法。 此方法为您添加cookie,并将默认的身份validation和质询方案设置为应用程序cookie IdentityConstants.ApplicationScheme 。 此外,它还将默认登录方案设置为外部cookie IdentityConstants.ExternalScheme 。
希望这对你有所帮助。
与@Serverin类似,设置Application Cookie的OnRedirectToLogin工作,但必须在startup.cs中的services.AddIdentity之后的语句中完成:ConfigureServices:
services.ConfigureApplicationCookie(options => { options.Events.OnRedirectToLogin = context => { context.Response.Headers["Location"] = context.RedirectUri; context.Response.StatusCode = 401; return Task.CompletedTask; }; });
这是CookieAuthenticationEvents.OnRedirectToLogin的源代码:
public Func, Task> OnRedirectToLogin { get; set; } = context => { if (IsAjaxRequest(context.Request)) { context.Response.Headers["Location"] = context.RedirectUri; context.Response.StatusCode = 401; } else { context.Response.Redirect(context.RedirectUri); } return Task.CompletedTask; };
您可以在从客户端进行API调用时向请求添加“X-Requested-With:XMLHttpRequest”标头。
我不知道如何生成401错误,但是如果你使用:
o.AccessDeniedPath = "{path to invalid}";
这将允许您在挑战失败时重定向某个位置。
执行此操作的另一种方法是使用AuthenticationSchemeOptions.EventsType
( 此处的另一个答案点 )是DI /测试友好型。 这将允许您将其他组件拉入解决过程。
这是一个示例,包括注册和解决方案,它停止默认重定向登录未经身份validation的请求,而只返回硬盘401
。 它还有一个插槽,可用于任何其他依赖项,可能需要了解未经身份validation的请求。
在Startup.cs
:
services .AddAuthentication("MyAuthScheme") .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.EventsType = typeof(MyEventsWrapper); }; ... services.AddTransient(); services.AddSingleton();
然后,在MyEventsWrapper.cs
:
public class MyEventsWrapper : CookieAuthenticationEvents { private readonly IHttpContextAccessor _accessor; private readonly IDependency _otherDependency; public MyEventsWrapper(IHttpContextAccessor accessor, IDependency otherDependency) { _accessor = accessor; _otherDependency = otherDependency; } public override async Task RedirectToLogin(RedirectContext context) { context.Response.Headers.Remove("Location"); context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; await _otherDependency.Cleanup(_accessor.HttpContext); } }