You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 16:28:13