导读:本期聚焦于画家创作的《Spring Boot 整合 JWT 实现令牌认证该怎么做?完整流程与代码详解》,敬请观看详情。JWT(JSON Web Token)是一种无状态的令牌认证方案,特别适合前后端分离架构。本文将围绕 Spring Boot 整合 JWT 展开,先讲清楚 JWT 的结构、签名算法与工作原理,再手把手演示如何在项目中引入依赖、编写工具类生成和解析令牌,配合拦截器或过滤器完成登录鉴权,最后补充令牌刷新、常见安全漏洞防范等实战要点,帮助你搭建一套安全可靠的用户认证体系。

做过前后端分离项目的人都知道,传统的 Session 认证在分布式场景下越来越吃力:服务端要保存会话状态,集群环境还得考虑 Session 共享,移动端对接也麻烦。JWT 的出现很好地解决了这个问题——把用户信息直接编码进令牌,服务端不需要存储任何会话数据,只要验签就能确认身份。这篇文章就以 Spring Boot 为例,完整讲一遍 JWT 的整合过程,从原理到落地代码全部覆盖。

Spring Boot 整合 JWT 实现令牌认证该怎么做?完整流程与代码详解

JWT 的结构与工作原理

JWT 由三部分组成,用点号分隔:Header.Payload.Signature。Header 描述令牌类型和签名算法,比如 HS256;Payload 是主体,存放声明(Claim),例如用户 ID、过期时间、签发者等;Signature 是对前两段内容用密钥计算出的签名,用于防止内容被篡改。

这里有个很多人容易忽略的点:Payload 默认只是 Base64Url 编码,并不加密。也就是说,谁拿到令牌都能解出里面的内容。所以绝对不要把密码、手机号这类敏感信息放进 Payload。JWT 解决的是防篡改问题,不是保密问题,两者不能混为一谈。

整个认证流程大致是这样的:用户登录成功后,服务端生成一个 JWT 返回给前端;前端把它存在 localStorage 或请求头里,之后每次请求都带上这个令牌;服务端收到请求后,用密钥重新计算签名与令牌中的签名比对,一致且未过期就放行。全程服务端不存任何东西,天然支持水平扩展。

引入依赖并编写 JWT 工具类

整合的第一步是引入依赖。常用的库是 jjwt,注意 0.11 版本之后需要显式引入 api 和 impl 两个包:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
&ltlt;dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

依赖就绪后,写一个 JWT 工具类,把生成、解析、校验三件事封装起来。密钥建议放在配置文件里,不要硬编码在代码中,而且密钥长度必须足够(HS256 至少 256 位),否则 jjwt 会直接抛异常:

@Component
public class JwtUtil {

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

    @Value("${jwt.expire}")  // 过期时间,单位毫秒
    private long expire;

    private SecretKey getKey() {
        return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
    }

    // 生成令牌
    public String createToken(Long userId, String username) {
        Date now = new Date();
        Date expiry = new Date(now.getTime() + expire);
        return Jwts.builder()
                .setSubject(String.valueOf(userId))
                .claim("username", username)
                .setIssuedAt(now)
                .setExpiration(expiry)
                .signWith(getKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    // 解析令牌,无效或过期会抛出异常
    public Claims parseToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(getKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    // 判断令牌是否有效
    public boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }
}

配置文件里这样写:jwt.secret 用一段足够长的随机字符串,jwt.expire 一般设为两小时左右。生成令牌时除了用户标识,还可以放角色、租户 ID 这类高频读取的字段,省去每次查库的开销。

登录发放令牌与拦截器鉴权

工具类写好之后,先实现登录接口。校验账号密码成功后调用 createToken 把令牌返回给前端:

@RestController
public class LoginController {

    @Autowired
    private UserService userService;
    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public Map<String, Object> login(@RequestBody LoginDTO dto) {
        User user = userService.checkPassword(dto.getUsername(), dto.getPassword());
        if (user == null) {
            throw new BusinessException("用户名或密码错误");
        }
        String token = jwtUtil.createToken(user.getId(), user.getUsername());
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        return result;
    }
}

接下来是关键的一步:用拦截器统一校验请求携带的令牌。前端通常把令牌放在请求头 Authorization 中,格式为 Bearer <token>。拦截器解析出用户信息后,可以塞进 HttpServletRequest 的 attribute 里,后续 Controller 直接取用:

@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith("Bearer ")) {
            response.setStatus(401);
            return false;
        }
        String token = header.substring(7);
        if (!jwtUtil.validateToken(token)) {
            response.setStatus(401);
            return false;
        }
        Claims claims = jwtUtil.parseToken(token);
        request.setAttribute("userId", Long.valueOf(claims.getSubject()));
        request.setAttribute("username", claims.get("username", String.class));
        return true;
    }
}

再写一个配置类注册拦截器,把登录、注册等公开接口排除在外。如果你用的是 Spring Security,也可以换成自定义的 OncePerRequestFilter 接入过滤链,思路是一样的,只是挂载位置不同。

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private JwtInterceptor jwtInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/register");
    }
}

令牌刷新与安全注意事项

JWT 最大的短板是签发后无法主动作废。如果用户改密码或账号被盗,旧令牌在过期前依然有效。常见的应对方案是双令牌机制:签发一个短效的 accessToken 和一个长效的 refreshToken,accessToken 过期后前端用 refreshToken 换新的。对于需要强制下线的场景,可以维护一个 Redis 黑名单,注销时把令牌的唯一标识 jti 存进去,拦截器校验时多查一次黑名单,牺牲一点无状态的纯粹性来换取可控性。

另外几点安全建议值得记牢:密钥不要写死在代码里,更不要提交到 Git 仓库,可以用环境变量或配置中心管理;令牌的有效期不要设太长,两小时以内比较稳妥;生产环境建议上 HTTPS,避免令牌在传输中被窃听;如果系统对权限要求细,别忘了在 Payload 里加角色声明,配合注解做接口级别的权限控制。

整体来看,Spring Boot 整合 JWT 并不复杂:一个工具类负责生成和解析,一个拦截器负责校验,再配合登录接口发令牌,核心链路就通了。真正决定系统安全的,是你在密钥管理、令牌生命周期和黑名单这些细节上的处理,把这些做到位,一套可靠的认证体系就成型了。

Spring BootJWT令牌认证修改时间:2026-09-03 04:56:34

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260903/49342.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。