ASP.NET Core MVC .NET 8:403状态码时如何显示自定义禁止视图?
解决ASP.NET Core MVC .NET 8中POST请求触发403时显示自定义禁止视图的问题
步骤1:创建返回自定义视图的Action
在AccountController(或你指定的控制器)中添加一个Action,用于返回Shared/ExtraPages/Forbidden.cshtml视图:
public IActionResult AccessDenied() { // 使用完整视图路径确保正确定位 return View("~/Views/Shared/ExtraPages/Forbidden.cshtml"); }
步骤2:修改Cookie认证配置,适配非GET请求的403处理
默认情况下,Cookie认证中间件对POST/PUT等非GET请求的403错误会返回空响应,我们需要重写事件逻辑,同时指定正确的AccessDeniedPath:
services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie(options => { options.LoginPath = "/Authorization/Login"; // 指向刚创建的AccessDenied Action options.AccessDeniedPath = "/Account/AccessDenied"; // 自定义403响应逻辑,处理非GET请求 options.Events.OnRedirectToAccessDenied = context => { if (!context.Request.Method.Equals("GET", StringComparison.OrdinalIgnoreCase)) { // 非GET请求直接返回403状态码和自定义视图内容 context.Response.StatusCode = StatusCodes.Status403Forbidden; context.Response.ContentType = "text/html"; // 手动渲染视图到响应体(需实现IViewRenderer服务) var viewRenderer = context.HttpContext.RequestServices.GetRequiredService<IViewRenderer>(); var viewContent = viewRenderer.RenderViewToStringAsync("~/Views/Shared/ExtraPages/Forbidden.cshtml", null).Result; return context.Response.WriteAsync(viewContent); } // GET请求正常重定向到AccessDenied页面 context.Response.Redirect(context.RedirectUri); return Task.CompletedTask; }; });
简化方案(无需自定义视图渲染)
如果不需要保留POST请求上下文,可让所有请求类型都重定向到AccessDenied页面:
options.Events.OnRedirectToAccessDenied = context => { context.Response.Redirect(context.RedirectUri); return Task.CompletedTask; };
这种方式会将POST请求重定向为GET请求到AccessDenied页面,用户将看到自定义禁止视图。
步骤3:实现IViewRenderer服务(可选,仅直接返回视图内容时需要)
若选择直接在非GET请求中返回视图内容,需实现视图渲染服务:
public interface IViewRenderer { Task<string> RenderViewToStringAsync(string viewPath, object model); } public class ViewRenderer : IViewRenderer { private readonly IRazorViewEngine _razorViewEngine; private readonly ITempDataProvider _tempDataProvider; private readonly IServiceProvider _serviceProvider; public ViewRenderer(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider) { _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; } public async Task<string> RenderViewToStringAsync(string viewPath, object model) { var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider }; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); using var sw = new StringWriter(); var viewResult = _razorViewEngine.FindView(actionContext, viewPath, false); if (!viewResult.Success) { throw new InvalidOperationException($"找不到视图: {viewPath}"); } var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model }; var viewContext = new ViewContext( actionContext, viewResult.View, viewDictionary, new TempDataDictionary(actionContext.HttpContext, _tempDataProvider), sw, new HtmlHelperOptions() ); await viewResult.View.RenderAsync(viewContext); return sw.ToString(); } }
然后在Program.cs中注册该服务:
services.AddScoped<IViewRenderer, ViewRenderer>();
步骤4:确认Action已应用授权属性
确保Create Action添加了[Authorize]属性(或对应策略),示例:
[HttpPost] [Authorize(Policy = ApplicationPolicies.Administrator)] public async Task<IActionResult> Create(CreateContentCommand command) { await mediator.Send(command); return Redirect($"{Url.Action("Index")}?pageName={command.PageName}"); }
验证自定义视图
确保~/Views/Shared/ExtraPages/Forbidden.cshtml存在并包含内容,示例:
@{ ViewData["Title"] = "禁止访问"; } <div class="alert alert-danger"> <h2>@ViewData["Title"]</h2> <p>你没有权限执行此操作,请联系系统管理员。</p> </div>
内容的提问来源于stack exchange,提问作者Firuz
相关产品推荐
相关产品推荐

