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中, AutomaticAuthenticateAutomaticChallenge属性旨在在单个身份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); } }