springboot+vue前后端分离项目加入jwt

目前只写了后端方面的,马上在补充一下前端的吧

1. 后端处理过程

依赖

复制代码
<!-- JJWT 核心 API -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.5</version>
    </dependency>
    <!-- JJWT 实现类(运行时依赖) -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
    <!-- JSON 序列化(Jackson) -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>

添加jwt配置文件

复制代码
# JWT 核心配置(必须添加)
jwt:
  # 密钥(必须是32位以上字符串,可随便写,生产环境要随机生成)
  secret: abcdefghijklmnopqrstuvwxyz1234567890abcdef
  # 过期时间(秒):10小时 = 36000秒
  expire-time: 36000
复制代码
mybatis-plus:
  global-config:
    banner: false  # 关闭 MyBatis-Plus 启动 Logo

目录结构

jwtutil.java

复制代码
package com.example.wms001.common;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;

@Component
public class JwtUtil {
    // 从配置文件读取密钥(application.yml 配置不变)
    @Value("${jwt.secret}")
    private String secret;

    // Token过期时间(秒)
    @Value("${jwt.expire-time}")
    private Long expireTime;

    // 生成密钥
    private SecretKey getSecretKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }

    // 生成Token(逻辑不变)
    public String generateToken(String userId, Map<String, Object> claims) {
        Date now = new Date();
        Date expireDate = new Date(now.getTime() + expireTime * 1000);

        return Jwts.builder()
                .setClaims(claims)
                .setSubject(userId)
                .setIssuedAt(now)
                .setExpiration(expireDate)
                .signWith(getSecretKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    // 解析Token(逻辑不变)
    public Claims parseToken(String token) {
        try {
            return Jwts.parserBuilder()
                    .setSigningKey(getSecretKey())
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException e) {
            throw new RuntimeException("Token已过期");
        } catch (JwtException e) {
            throw new RuntimeException("Token无效");
        }
    }

    // 获取用户ID(逻辑不变)
    public String getUserIdFromToken(String token) {
        return parseToken(token).getSubject();
    }

    // 验证Token(逻辑不变)
    public boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

jwt拦截器Jwtinterceptr.java

复制代码
package com.example.wms001.common;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import jakarta.servlet.http.HttpServletRequest; // 关键:jakarta而非javax
import jakarta.servlet.http.HttpServletResponse;

@Component
public class JwtInterceptor implements HandlerInterceptor {
    @Autowired
    private JwtUtil jwtUtil; // 注入common包的JwtUtil

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 排除登录接口
        String requestURI = request.getRequestURI();
        if (requestURI.contains("/user/login")) {
            return true;
        }

        // 获取Token
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            throw new RuntimeException("请先登录");
        }
        token = token.replace("Bearer ", "");

        // 验证Token
        if (!jwtUtil.validateToken(token)) {
            throw new RuntimeException("Token无效或已过期");
        }

        // 存入用户ID到请求域
        String userId = jwtUtil.getUserIdFromToken(token);
        request.setAttribute("userId", userId);

        return true;
    }
}

配置文件

复制代码
package com.example.wms001.common;

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

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private JwtInterceptor jwtInterceptor; // 注入common包的拦截器

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/login");
    }
}
相关推荐
Conan在掘金18 分钟前
鸿蒙 ArkUI 进阶:@Extend 和 @Styles,把样式也抽成「乐高块」的正确姿势
后端
orient26 分钟前
为什么需要并发编程
后端
Cosolar32 分钟前
AI Agent 架构原理详解:从一次提问到任务完成的完整闭环
人工智能·后端·架构
zithern_juejin36 分钟前
深入理解 Vue 响应式原理:从 Object.defineProperty 到 Proxy 的全面进化
vue.js
Conan在掘金40 分钟前
鸿蒙 ArkUI 深水区:Stage 模型多维状态,从「组件内」跳到「应用级」的分水岭
后端
长栎1 小时前
用AI优化Redis缓存失效,我把热key问题想简单了
后端
面试鸭1 小时前
我说我们做 Agent 从来不怕死循环,面试官调出兜底日志:“第 47 次强制终止,是你半夜爬起来按停的?”
后端·面试·求职
小小猪的春天1 小时前
团队级 Code Review Skill 实践:4个人、4个AI、1套规则,CR从找bug变成做决策
后端·架构
长栎1 小时前
AI帮我写了个Spring Boot校验,线上漏掉了这组边界条件
后端
外滩运维专家1 小时前
Let's Encrypt 的 ACME 协议到底干了什么?用抓包带你看一遍
后端