.NET Core 2.0授权过滤器引发内部服务器错误问题咨询
这个问题我之前也碰到过,是.NET Core 2.0对身份验证系统做了重构导致的——和1.1版本不同,2.0要求必须明确配置身份验证方案或者默认挑战方案,否则使用[Authorize]过滤器就会触发500错误,而不是预期的401未授权。
问题复现步骤
- 创建一个无身份验证的.NET Core 2.0 MVC新项目
- 在控制器方法上添加
[Authorize]特性,代码示例:
[Authorize] public IActionResult Contact() { ViewData["Message"] = "Your contact page."; return View(); }
- 访问该方法对应的URL,会返回
500 Internal Server Error,而在.NET Core 1.1中相同代码会正确返回401 Unauthorized响应
抛出的异常信息
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. at Microsoft.AspNetCore.Authentication.AuthenticationService.<ChallengeAsync>d__11.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.ChallengeResult.<ExecuteResultAsync>d__14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeResultAsync>d__19.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeFilterPipelineAsync>d__17.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeAsync>d__15.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()
解决方案
针对这个问题,有两种常见的解决方式,你可以根据项目需求选择:
方案一:配置默认身份验证挑战方案(适合后续要添加完整身份验证的场景)
在Startup.cs的ConfigureServices方法中,显式配置默认的挑战方案,同时启用身份验证中间件:
- 配置身份验证服务:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // 添加身份验证配置,指定默认挑战方案 services.AddAuthentication(options => { // 这里可以先临时用占位符,后续替换为实际的方案(比如CookieAuthenticationDefaults.AuthenticationScheme) options.DefaultChallengeScheme = "oidc"; }); }
- 在
Configure方法中启用身份验证中间件(注意要放在UseMvc之前):
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseAuthentication(); // 启用身份验证中间件 app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
方案二:配置默认授权策略(适合简单限制未登录用户访问的场景)
如果你的项目不需要复杂的身份验证逻辑,只是想限制未登录用户访问特定接口,可以直接配置默认的授权策略:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { // 创建要求用户已认证的授权策略 var authPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); // 将策略添加为全局过滤器 options.Filters.Add(new AuthorizeFilter(authPolicy)); }); // 配置基础的Cookie身份验证方案(即使只是空配置) services.AddCookieAuthentication(options => { options.Cookie.Name = "MyAppAuthCookie"; }); }
同样要记得在Configure方法中启用UseAuthentication中间件。
原因说明
.NET Core 2.0对身份验证系统进行了大幅重构,移除了1.1版本中的隐式默认行为,要求开发者必须显式指定身份验证方案或默认挑战方案,这样框架才能知道在用户未认证时应该使用哪种方式发起挑战(比如跳转登录页、返回401等),否则就会抛出你看到的InvalidOperationException异常。
内容的提问来源于stack exchange,提问作者Marko
相关产品推荐
相关产品推荐

