Spring Security自定义403页面有两种方式:一是通过accessDeniedPage("/403.html")配置跳转静态页;二是实现AccessDeniedHandler接口,手动设置状态码为403并返回JSON或重定向,适用于前后端分离场景。

HTML 文件本身不能“创建”403 页面,它只能作为 403 响应的展示内容;真正的 403 状态码必须由服务器(如 Nginx、Apache)或后端框架(如 Spring Security)主动返回——否则你打开 403.html 得到的永远是 200 OK。
为什么直接访问 403.html 是 200 而不是 403
这是最常踩的坑:把 403.html 放进网站根目录,然后在浏览器里输 https://yoursite.com/403.html,服务器只是把它当普通静态文件返回,压根没走权限校验逻辑。状态码是 200,完全起不到测试或提示作用。
- 403 是服务器对「某个受控请求」做出的决策结果,不是文件名触发的
- 你访问
/admin,后端检查登录态失败 → 主动返回403+ 渲染403.html - 你访问
/secret/config.json,Nginx 配置了deny all→ 直接返回403+ 静态403.html - 你直接请求
/403.html→ 无校验,200返回,纯展示
Nginx 中配置 error_page 显示自定义 403 页面
关键不是放文件,而是让 Nginx 在真正发生 403 时用你的 HTML 替换默认响应。配置必须包含 error_page 和 internal,否则可能被绕过。
-
error_page 403 /403.html要写在http、server或location块内 - 对应路径需能被 Nginx 读取:
root或alias必须指向403.html所在目录 - 必须加
location = /403.html { internal; },防止用户直接 GET 绕过权限逻辑 - 别漏掉 MIME 类型支持,确保
types模块已加载,否则可能返回空白页
Spring Security 中配置自定义 403 页面
Spring Boot + Spring Security 不会自动把 403.html 当作错误页,得显式指定跳转逻辑或处理器。
实现 Markdown↔ HTML 互转,支持导出 PDF,用于用户请求的文档格式转换。
立即学习“前端免费学习笔记(深入)”;
- 用
.accessDeniedPage("/403")配合一个返回403.html的@Controller,注意该接口要允许匿名访问 - 更稳妥的方式是实现
AccessDeniedHandler,手动设置响应状态码为HttpServletResponse.SC_FORBIDDEN,再 forward 到/403.html - 如果用了 Thymeleaf,可直接返回
"403"视图名,但需确认模板路径和Content-Type正确 - 别依赖
exceptionHandling().accessDeniedPage()单独生效——它只对基于表达式的鉴权失败有效,对hasRole等配置可能不触发
403 页面 HTML 本身要注意什么
它虽是静态文件,但得经得起真实环境检验,尤其别依赖 JS 或外部资源。
-
<title></title>标签里必须含403字样,比如<title>403 - 权限不足</title>,否则搜索引擎和屏幕阅读器无法识别语义 - 所有 CSS 写成内联样式或
<style></style>块,避免因路径错误导致白屏 - 按钮链接用相对路径或完整 URL,别写
javascript:history.back()这类不可靠回退 - 预留
<meta name="robots" content="noindex">,防止被搜索收录成正常页面 - 字体大小用
rem或em,配合媒体查询做基础响应式,手机端至少保证文字可读、按钮可点
最容易被忽略的是:403 页面从来不是独立存在的,它必须嵌入到完整的权限链路中——从请求发起、服务端拦截、状态码生成,再到 HTML 渲染,每一步断掉,它就只是个普通 HTML 文件。

















