如何实现仅登录用户可访问受保护HTML页面(原生JS+Spring Boot)
原生HTML/CSS/JS + Spring Boot 受保护页面访问控制方案
纯前端拦截可通过浏览器控制台篡改脚本、直接输入资源地址等方式绕过,必须搭配后端权限校验做兜底,以下方案完全适配原生前端+Spring Boot技术栈,无需引入任何第三方框架
一、前端侧基础拦截逻辑
前置约定
- 建议把所有需要登录才能访问的HTML页面统一放到项目目录的
protected/文件夹下,公共页面(登录页、公开首页等)放到根目录,公共css、js、图片资源放到对应css/、js/、assets/目录,方便后续配置拦截规则。 - 登录成功后后端返回的认证凭证(如JWT)统一存在
localStorage,key固定为auth_token。
1. 全局登录态校验脚本
把下面的代码存为auth-check.js,在所有受保护HTML页面的<head>标签最顶部引入,保证它在页面其他所有资源、脚本之前执行,避免未登录用户提前看到页面内容。
(function() { const token = localStorage.getItem('auth_token'); // 无凭证直接跳登录页,携带当前页地址方便登录后跳回 if (!token) { const targetUrl = encodeURIComponent(window.location.href); window.location.replace(`/login.html?redirect=${targetUrl}`); return; } // 本地预校验token有效性,减少无效请求 try { const payload = JSON.parse(atob(token.split('.')[1])); // token过期直接清除跳登录 if (payload.exp * 1000 < Date.now()) { localStorage.removeItem('auth_token'); const targetUrl = encodeURIComponent(window.location.href); window.location.replace(`/login.html?redirect=${targetUrl}`); } } catch (err) { // token格式非法直接清除跳登录 localStorage.removeItem('auth_token'); const targetUrl = encodeURIComponent(window.location.href); window.location.replace(`/login.html?redirect=${targetUrl}`); } })();
受保护页面引入示例:
<!DOCTYPE html> <html lang="zh-CN"> <head> <!-- 第一行引入校验脚本 --> <script src="/js/auth-check.js"></script> <meta charset="UTF-8"> <title>受保护页面</title> <!-- 后续再引入其他css、js资源 --> </head> <body> <!-- 页面内容 --> </body> </html>
2. 全局Fetch请求封装
替换项目中直接调用fetch的逻辑,统一封装请求方法,自动携带认证头、全局处理401未授权响应,不用每个接口单独写校验逻辑。把下面的代码存为request.js,在所有页面(包括公共页面)引入。
window.request = async function(url, options = {}) { const token = localStorage.getItem('auth_token'); const defaultConfig = { headers: { 'Content-Type': 'application/json', ...(token ? { 'Authorization': `Bearer ${token}` } : {}) }, credentials: 'same-origin', ...options }; const response = await fetch(url, defaultConfig); // 全局处理401:清除失效凭证跳登录 if (response.status === 401) { localStorage.removeItem('auth_token'); const targetUrl = encodeURIComponent(window.location.href); window.location.replace(`/login.html?redirect=${targetUrl}`); return Promise.reject(new Error('登录已失效,请重新登录')); } return response; }
3. 登录页逻辑适配
登录接口调用成功后,把后端返回的token存入本地存储,再跳转到用户之前访问的目标页:
// 登录表单提交逻辑示例 async function handleLoginSubmit(username, password) { const res = await request('/api/auth/login', { method: 'POST', body: JSON.stringify({ username, password }) }); const result = await res.json(); // 存储后端返回的有效token localStorage.setItem('auth_token', result.token); // 读取跳转参数,没有则默认跳首页 const searchParams = new URLSearchParams(window.location.search); const redirectUrl = searchParams.get('redirect') ? decodeURIComponent(searchParams.get('redirect')) : '/index.html'; window.location.replace(redirectUrl); }
二、Spring Boot后端兜底校验(必须实现)
前端校验只能提升用户体验,无法真正阻止未授权访问,必须在后端配置两层拦截。
1. 自定义权限拦截器
创建拦截器类,同时校验受保护静态页面、后端接口的访问权限:
@Component public class AuthInterceptor implements HandlerInterceptor { // 替换成你项目里的JWT签名密钥 private static final String SIGN_KEY = "你的项目认证签名密钥"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 从请求头取token String authHeader = request.getHeader("Authorization"); boolean tokenValid = false; // 校验token有效性:验签、判断是否过期 if (authHeader != null && authHeader.startsWith("Bearer ")) { String token = authHeader.substring(7); try { Jwts.parser().setSigningKey(SIGN_KEY).parseClaimsJws(token); tokenValid = true; } catch (Exception ignored) {} } if (!tokenValid) { String acceptHeader = request.getHeader("Accept"); // 页面请求直接302跳登录页,接口请求返回401状态码 if (acceptHeader != null && acceptHeader.contains("text/html")) { response.sendRedirect("/login.html"); } else { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); } return false; } return true; } }
2. 注册拦截器规则
创建Web配置类,指定拦截路径和放行路径:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private AuthInterceptor authInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor) // 拦截受保护页面目录、所有业务接口 .addPathPatterns("/protected/**", "/api/**") // 放行登录页、登录接口、公共静态资源 .excludePathPatterns( "/login.html", "/api/auth/login", "/css/**", "/js/**", "/assets/**" ); } }
三、补充说明
- 如果对安全性要求更高,建议把认证凭证存在
HttpOnly属性的Cookie中,可以避免XSS攻击窃取token,这种场景下前端不需要手动拼接Authorization请求头,浏览器会自动携带Cookie,只要把auth-check.js里的本地token校验逻辑改成调用后端提供的/api/auth/check接口判断登录态即可。 - 退出登录逻辑:调用后端退出接口(如果是Cookie模式),清除本地存储的
auth_token,再跳转到登录页即可。 - 敏感数据不要直接写在静态HTML代码里,所有敏感内容都通过接口向后端拉取,避免静态资源意外泄露数据。
内容的提问来源于stack exchange,提问作者Fatima22
相关产品推荐
相关产品推荐

