ASP.NET Core Web API 项目在 Controller Action 中 return Forbid()
时报错 "No authenticationScheme was specified, and there was no DefaultForbidScheme found"
错误日志如下:
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultForbidScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).
at Microsoft.AspNetCore.Authentication.AuthenticationService.ForbidAsync(HttpContext context, String scheme, AuthenticationProperties properties)
at Microsoft.AspNetCore.Mvc.ForbidResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultFilters>g__Awaited|27_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at NSwag.AspNetCore.Middlewares.SwaggerUiIndexMiddleware.Invoke(HttpContext context)
at NSwag.AspNetCore.Middlewares.RedirectToIndexMiddleware.Invoke(HttpContext context)
at NSwag.AspNetCore.Middlewares.OpenApiDocumentMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
请问如何解决?
加上 default scheme 问题依旧
services.AddAuthentication(options =>
{
options.DefaultScheme = "cnblogs";
options.DefaultForbidScheme = "cnblogs";
});
找到了一种解决方法,使用 ProblemDetails
return Problem(statusCode: 403);
找到了更简单的解决方法
return StatusCode(403);
Forbid()
方法会寻找AuthenticationScheme
来决定如何返回403响应(如cookie认证策略Forbid()时会重定向到配置好的登录页面),这个异常可能是没有设置默认的AuthenticationScheme
导致的,webapi如果用了JWT认证那么应该设置DefaultAuthenticationScheme
为JwtBearerDefaults.AuthenticationScheme
同时调用AddJwtBearer
注册相关的服务,如果使用了Cookie
认证,那么就是CookieAuthenticationDefaults.AuthenticationScheme
然后调用AddCookie
// jwt
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(...);
// or cookie
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
. AddCookie(...);
如果在没有配置使用身份认证的情况,返回Problem应该是个不错的方案;如果不想服务有身份认证,又想在Controller中用Forbid()
,那么就仅在注册服务时注册身份认证相关服务,中间件配置中不调用app.UseAuthentication();app.UseAuthorization();
就行
试了 pp.UseAuthentication();app.UseAuthorization();
,问题依旧
根源是 ForbidResult 的实现中调用了 httpContext.ForbidAsync
(详见 ForbidResult.cs#L116),这个设计有问题,我记得以前好像不是怎么设计的,ForbidResult 老老实实返回 403 状态就行了,如果要执行 httpContext.ForbidAsync
,在 middleware 中处理。
知道了这个原因,解决起来就容易了,本来就是想返回个 403 状态码,直接 return StatusCode(403);