当前位置: 首页 > article >正文

Vue3 + Spring Boot集成JWT认证

一、JWT令牌详解:新一代无状态身份验证方案

JWT(JSON Web Token) 是一种开放标准(RFC 7519),用于在各方之间安全传输JSON对象。它以紧凑的URL安全字符串形式传递信息,适合用于无状态身份验证场景,例如前后端分离应用。

1. JWT结构拆解

一个JWT令牌由三部分组成,格式为:
Header.Payload.Signature
通过 . 连接(例:xxxxx.yyyyy.zzzzz

  1. Header(头)

    <JSON>

    {
      "alg": "HS256",  // 加密算法(如HS256, RS256)
      "typ": "JWT"     // 类型固定为JWT
    }
  2. Payload(载荷)

    <JSON>

    {
      "sub": "user123",       // 用户标识(标准字段)
      "name": "John Doe",     // 自定义声明
      "iat": 1664448000,      // 签发时间
      "exp": 1665052800       // 过期时间
    }
  3. Signature(签名)
    签名由Header、Payload和密钥生成,确保数据完整性:

    HMACSHA256(
      base64UrlEncode(header) + "." + base64UrlEncode(payload),
      secret-key
    )
    

2. JWT核心优势
  • 无状态性:服务端无需保存会话信息,天然适合分布式系统
  • 安全性:数字签名防止篡改,结合HTTPS抵御中间人攻击
  • 跨域友好:Token可轻松传递至不同域名的前端
  • 扩展性:通过Payload自定义业务字段(如用户权限角色)

二、实战:Vue3 + Spring Boot集成JWT认证

1. 后端(Spring Boot)JWT配置
步骤1:添加Maven依赖

<XML>

<!-- JWT支持 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
步骤2:生成与验证JWT的工具类

<JAVA>

@Component
public class JwtUtils{

    @Value("${jwt.secret}")
    private String jwtSecret;//从yaml文件中jwt.secret中读取数据

    @Value("${jwt.expiration}")
    private int jwtExpirationMs;

    // 生成密钥对象(用于HS256)
    private SecretKey getSigningKey() {
        return Keys.hmacShaKeyFor(jwtSecret.getBytes());
    }

    // 生成令牌
    public String generateToken(User user) {
        return Jwts.builder()
                .subject(user.getUsername())//设置负载部分
                .issuedAt(new Date())
                .expiration(new Date((new Date()).getTime() + jwtExpirationMs))//设置令牌有效期
                .signWith(getSigningKey())//设置密钥
                .compact();
    }

    // 解析令牌
    public Claims parseToken(String token) {
        return Jwts.parser()
                .verifyWith(getSigningKey())
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }

    // 验证令牌有效性
    public boolean validateToken(String token) {
        try {
            parseToken(token); // 自动校验签名和过期时间
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            // 处理具体异常类型
            return false;
        }
    }

    // 从令牌获取用户名
    public String getUsernameFromToken(String token) {
        return parseToken(token).getSubject();
    }
}
在application.yaml文件中添加字段信息!!后面会有写道
步骤3:创建拦截器拦截请求解析token令牌

<JAVA>

​
package com.zht.interceptor;

import com.zht.utils.JwtUtils;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Slf4j
@Component
public class CustomInterceptor implements HandlerInterceptor {


    @Autowired
    private JwtUtils jwtUtils;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.获取请求头中的令牌
        String authHeader = request.getHeader("Authorization");
        String accept = request.getHeader("Accept");
        log.info("{}",accept);
        log.info("请求发送成功,正在验证令牌合理性");
        if (authHeader == null ) {
            throw new Exception("Authorization为空");
        }
        //根据前端设置的响应头为准如果前端响应头没有编写前缀不需要做校验注释掉以下代码即可
        if(!authHeader.startsWith("Bearer ")){
            throw new Exception("无效的Authorization头格式,需要Bearer token");
        }

        log.info("请求发送成功,正在验证令牌合理性");

        // 2.提取JWT令牌
        String token = authHeader.substring(7);

        try {
            // 3.解析验证令牌(示例密钥,实际应从配置读取)
            jwtUtils.parseToken(token);
            log.info("令牌验证成功");
            return true; // 验证通过
        } catch (ExpiredJwtException e) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Token expired");
        } catch (JwtException e) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Invalid token");
        }
        return false;
    }

}
步骤4:创建实现WebMvcConfigurer接口的实现类,使上面自定义的拦截器生效,顺便解决跨域问题

<JAVA>

package com.zht.interceptor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Autowired
    private CustomInterceptor customInterceptor;
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 允许所有路径
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")  // 允许的请求方法
                .allowedHeaders("*")  // 允许所有 Header
                .maxAge(3600);  // 预检请求的缓存时间(单位:秒)
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(customInterceptor)
                .addPathPatterns("/api/**") 
                .excludePathPatterns("/api/login/**", "/api/register/**");//这里修改为自己的接口路径
    }
}

2. 前端(Vue3)Token管理
步骤1:登录接口获取Token,使用LocalStorage持久化存储到本地

<JAVASCRIPT>

// 登录请求示例
const login = () => {
  axios.post('/api/auth/login', { username, password })
    .then(res => {
      localStorage.setItem('token', res.data.token);  // 存储Token至本地
      router.push('/dashboard');  // 跳转至你的项目首页面
    });
};
步骤2:请求拦截器自动附加Token

<JAVASCRIPT>

// Axios拦截器配置(src/utils/http.js)
import axios from 'axios';

const http = axios.create({ baseURL: '/api' });

http.interceptors.request.use(config => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

http.interceptors.response.use(
  response => response,
  error => {
    if (error.response.status === 401) {
      // 处理Token过期:跳转登录页并清除本地Token
      localStorage.removeItem('token');
      router.push('/login');
    }
    return Promise.reject(error);
  }
);

export default http;
步骤3:页面路由守卫验证权限

<JAVASCRIPT>

// router.js配置
router.beforeEach((to, from, next) => {
  const isAuthenticated = localStorage.getItem('token') !== null;
  
  if (to.meta.requiresAuth && !isAuthenticated) {
    next('/login');
  } else {
    next();
  }
});

三、安全最佳实践

  1. 密钥管理

    • 避免硬编码密钥,通过环境变量(application.yml)注入

    <YAML>

    jwt:
      secret: ${JWT_SECRET:default-secret}
      expiration-ms: 3600000
  2. Token存储

    • 推荐使用HttpOnly Cookie减少XSS攻击风险
    • 若存localStorage,需代码加密(如jsencrypt库)
  3. Token刷新机制

    • 短期Token(5分钟)+ 长有效期Refresh Token,减少泄露风险
    • 设计/api/auth/refresh接口刷新Token

四、对比传统会话认证

特性JWTSession
存储位置客户端服务端
扩展性适合分布式/微服务需Session共享方案
安全性Signature防篡改Cookie属性控制(如Secure、SameSite)
性能影响每次请求携带完整Token服务端需查询Session

总结:JWT为现代Web应用提供了简洁、安全的无状态认证方案。结合Spring Boot与Vue3的全栈实现,可快速搭建高可用身份验证流程。合理运用Token过期、刷新策略和加密存储,可大幅提升系统安全性。


http://www.kler.cn/a/582231.html

相关文章:

  • 【实战ES】实战 Elasticsearch:快速上手与深度实践-7.2.2自动扩缩容策略(基于HPA)
  • 【数据结构】1数据结构基本概念 【作业1数据结构综述】
  • 力扣hot100_普通数组
  • 【odoo17】odoo前端视图的结构分析及新增视图类型的实现
  • C++竞赛级输入输出优化实战
  • 通过Golang的container/list实现LRU缓存算法
  • 大数据任务调度:DolphinScheduler、Airflow 实战(调度策略、任务依赖)
  • Python基于深度学习的电影评论情感分析可视化系统(全新升级版)【附源码、参考文档】
  • 【每日学点HarmonyOS Next知识】拖拽调整列表顺序、tab回弹、自定义弹窗this、状态变量修饰枚举
  • 工作中,当遇到要把http请求变成https时 怎么处理
  • spring 的model repository service controller的功能
  • Yashan DB 文件管理
  • 《深度剖析架构蒸馏与逻辑蒸馏:探寻知识迁移的差异化路径》
  • 【音视频】ffmpeg命令提取像素格式
  • 20250212:linux系统DNS解析卡顿5秒的bug
  • 在 Spring Boot 2.7.x 中引入 Kafka-0.9 的实践
  • vscode 好用插件
  • MySQL-储存引擎
  • 深度解析:如何在 Vue 3 中安全访问子组件实例
  • 使用STM32CubeMX配置定时器中断实现LED每秒闪烁一次(STM32G070CBT6)