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

如何实现仅登录用户可访问受保护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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 01:09:24