SpringBoot整合JWT实现Token认证与自动刷新

 更新时间:2026年07月20日 08:42:05   作者:张老师技术栈  
还在为分布式环境下的Session共享头疼吗?本文带你彻底搞懂JWT(JSON Web Token)方案,从结构解析到工具类封装,覆盖登录、刷新、拦截器校验和前端调用全流程,最后还总结了安全注意事项,一篇文章让你轻松实现无状态认证,告别Session烦恼,需要的朋友可以参考下

Session 方式在分布式环境下不好用,JWT(JSON Web Token)是目前主流的无状态认证方案。服务端不需要存 Session,Token 中包含了用户信息。

一、JWT 结构

header.payload.signature

header: 加密算法
payload: 用户数据(不要放密码)
signature: 签名,防止篡改

二、JWT 工具类

@Component
public class JwtUtil {

    @Value("${jwt.secret:mySecretKey}")
    private String secret;

    @Value("${jwt.expire:86400000}")
    private long expire;  // 默认24小时

    public String generateToken(Long userId, String username) {
        Date now = new Date();
        return Jwts.builder()
            .setSubject(userId.toString())
            .claim("username", username)
            .setIssuedAt(now)
            .setExpiration(new Date(now.getTime() + expire))
            .signWith(SignatureAlgorithm.HS256, secret)
            .compact();
    }

    public Claims parseToken(String token) {
        return Jwts.parser()
            .setSigningKey(secret)
            .parseClaimsJws(token)
            .getBody();
    }

    public boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

三、登录接口

@RestController
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public ResultVO<Map<String, Object>> login(
            @RequestParam String username,
            @RequestParam String password) {
        // 校验用户名密码
        if (!"admin".equals(username) || !"123456".equals(password)) {
            return ResultVO.error(401, "用户名或密码错误");
        }

        // 生成 Token
        String accessToken = jwtUtil.generateToken(1001L, username);
        String refreshToken = jwtUtil.generateRefreshToken(1001L);

        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", accessToken);
        result.put("refreshToken", refreshToken);
        result.put("expiresIn", 86400);

        return ResultVO.success(result);
    }
}

四、Token 刷新

@PostMapping("/refresh")
public ResultVO<Map<String, Object>> refresh(
        @RequestParam String refreshToken) {
    if (!jwtUtil.validateToken(refreshToken)) {
        return ResultVO.error(401, "RefreshToken 无效");
    }

    Claims claims = jwtUtil.parseToken(refreshToken);
    Long userId = Long.parseLong(claims.getSubject());
    String username = claims.get("username", String.class);

    String newAccessToken = jwtUtil.generateToken(userId, username);
    String newRefreshToken = jwtUtil.generateRefreshToken(userId);

    return ResultVO.success(Map.of(
        "accessToken", newAccessToken,
        "refreshToken", newRefreshToken
    ));
}

五、拦截器校验

@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            throw new BusinessException(401, "未登录");
        }

        token = token.substring(7);
        if (!jwtUtil.validateToken(token)) {
            throw new BusinessException(401, "Token 已过期");
        }

        // 将用户信息存入请求上下文
        Claims claims = jwtUtil.parseToken(token);
        request.setAttribute("userId", claims.getSubject());
        request.setAttribute("username", claims.get("username"));

        return true;
    }
}

六、前端调用

// 登录
const resp = await fetch('/auth/login', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({username: 'admin', password: '123456'})
});
const { accessToken, refreshToken } = await resp.json();

// 后续请求携带 Token
fetch('/api/user', {
    headers: {'Authorization': 'Bearer ' + accessToken}
});

// Token 过期时用 refreshToken 刷新
async function refreshAccessToken() {
    const resp = await fetch('/auth/refresh', {
        method: 'POST',
        body: new URLSearchParams({refreshToken})
    });
    const data = await resp.json();
    accessToken = data.accessToken;
}

七、安全注意事项

// 1. JWT 中不要放敏感信息
Claims claims = Jwts.parser()
    .setSigningKey(secret)
    .parseClaimsJws(token)
    .getBody();
String password = claims.get("password");  // ❌ 错误!

// 2. 密钥不要写死,用配置中心或环境变量
@Value("${jwt.secret}")
private String secret;

// 3. accessToken 有效期短(15-30分钟)
// refreshToken 有效期长(7天),专门用来刷新 accessToken

总结

Session 认证:服务端存 Session,分布式下需要共享 Session
JWT 认证: 无状态,Token 携带用户信息,适合分布式

JWT 缺点:签发后无法主动失效(只能等过期)
解决方案:accessToken 短时效 + refreshToken 刷新机制

到此这篇关于SpringBoot整合JWT实现Token认证与自动刷新的文章就介绍到这了,更多相关SpringBoot Token认证与自动刷新内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java后台处理Json格式数据的方法

    Java后台处理Json格式数据的方法

    这篇文章主要介绍了Java后台处理Json格式数据的方法的相关资料,非常不错具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • mybatis-plus的多租户不同版本实现的两种方式

    mybatis-plus的多租户不同版本实现的两种方式

    本文主要介绍了mybatis-plus的多租户不同版本实现的两种方式,Mybatis Plus 3.4.0版本之后多租户的实现,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • 深层剖析java应用开发中MyBayis缓存

    深层剖析java应用开发中MyBayis缓存

    这篇文章主要为大家深层剖析java开发中MyBayis缓存,文中讲解了Mybatis缓存的分类以及使用的方式,有需要的朋友可以借鉴参考下,希望可以有所帮助
    2021-09-09
  • Java四种权限修饰符知识点详解

    Java四种权限修饰符知识点详解

    在本篇文章里小编给大家分享的是关于Java四种权限修饰符知识点详解内容,需要的朋友们可以参考下。
    2020-05-05
  • springmvc分层领域模型概念详解

    springmvc分层领域模型概念详解

    本文核心为分层领域模型(VO , PO , BO, DAO ,POJO等)概念的个人理解,结合springmvc浅谈分层领域模型的相关知识,感兴趣的朋友跟随小编一起看看吧
    2021-08-08
  • Springboot整合第三方登录功能的实现示例

    Springboot整合第三方登录功能的实现示例

    本文主要介绍了Springboot整合第三方登录功能的实现示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • 阿里资深技术专家:在各阶段中3年经验的java程序员应该具备哪些技术能力

    阿里资深技术专家:在各阶段中3年经验的java程序员应该具备哪些技术能力

    这篇文章主要介绍了阿里资深技术专家:在各阶段中3年经验的java程序员应该具备哪些技术能力,本文给大家列举了一些内容,大家可以根据自己需要有方法的掌握,感兴趣的朋友跟随小编一起看看吧
    2020-07-07
  • Spring Boot中使用Spring-data-jpa的配置方法详解

    Spring Boot中使用Spring-data-jpa的配置方法详解

    今天小编就为大家分享一篇关于Spring Boot中使用Spring-data-jpa的配置方法详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • Java如何在Map中存放重复key

    Java如何在Map中存放重复key

    这篇文章主要介绍了Java如何在Map中存放重复key,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • Java二分查找算法实现代码实例

    Java二分查找算法实现代码实例

    这篇文章主要介绍了Java二分查找算法实现代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11

最新评论