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

Java JWT 技术详解与实践指南


Java JWT 技术详解与实践指南


1. JWT 基础概念

JWT (JSON Web Token) 是一种开放标准(RFC 7519),用于在各方之间安全传输信息的紧凑且自包含的方式。常用于身份验证和授权场景。

1.1 JWT 结构

JWT 由三部分组成,用 . 分隔:

Header.Payload.Signature
  • Header:包含令牌类型和签名算法(如 HS256、RS256)
  • Payload:存放有效信息(如用户ID、角色、过期时间)
  • Signature:验证令牌完整性和来源的签名

2. Java JWT 实现选型

2.1 常用库对比

库名称特点Maven 依赖
JJWT简单易用,文档完善io.jsonwebtoken:jjwt-api:0.12.3
Nimbus JOSE功能全面,支持更多JOSE规范com.nimbusds:nimbus-jose-jwt:9.37

3. 快速入门示例(使用 JJWT)

3.1 添加依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.12.3</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.12.3</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.12.3</version>
    <scope>runtime</scope>
</dependency>

3.2 生成 JWT

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;

public String generateToken(String username) {
    return Jwts.builder()
        .setSubject(username)
        .setIssuedAt(new Date())
        .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1小时
        .signWith(SignatureAlgorithm.HS256, "your-256-bit-secret")
        .compact();
}

3.3 解析验证 JWT

public String parseToken(String token) {
    try {
        return Jwts.parserBuilder()
            .setSigningKey("your-256-bit-secret")
            .build()
            .parseClaimsJws(token)
            .getBody()
            .getSubject();
    } catch (Exception e) {
        throw new RuntimeException("Invalid JWT");
    }
}

4. 最佳实践

4.1 安全配置

  • 密钥管理:使用至少256位的安全密钥
  • 过期时间:短期令牌(15-60分钟)结合刷新令牌
  • 敏感信息:不要在Payload中存储密码等敏感数据

4.2 与 Spring Security 集成

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/api/auth/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

public class JwtFilter extends OncePerRequestFilter {
    
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) 
                                    throws ServletException, IOException {
        String token = extractToken(request);
        if (token != null && validateToken(token)) {
            Authentication auth = getAuthentication(token);
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
        filterChain.doFilter(request, response);
    }
    
    private String extractToken(HttpServletRequest request) {
        String header = request.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            return header.substring(7);
        }
        return null;
    }
}

5. 高级功能

5.1 自定义 Claims

Map<String, Object> claims = new HashMap<>();
claims.put("roles", Arrays.asList("USER", "ADMIN"));

Jwts.builder()
    .setClaims(claims)
    // ...其他配置

5.2 刷新令牌机制

public String refreshToken(String oldToken) {
    Claims claims = parseClaims(oldToken);
    if (claims.getExpiration().before(new Date())) {
        throw new RuntimeException("Token expired");
    }
    return generateToken(claims.getSubject());
}

6. 常见问题解决方案

6.1 签名验证失败

  • 检查密钥是否一致
  • 验证算法是否匹配
  • 确认令牌未被篡改

6.2 跨服务验证(RS256 算法)

// 生成密钥对
KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);

// 使用私钥签名
Jwts.builder().signWith(keyPair.getPrivate(), RS256)...

// 使用公钥验证
Jwts.parserBuilder().setSigningKey(keyPair.getPublic())...

7. 性能优化建议

  1. 缓存公钥:RS256算法中避免每次请求都读取公钥
  2. 异步验证:使用CompletableFuture进行并行验证
  3. 精简Claims:减少Payload数据量

8. 安全注意事项

  • 始终使用HTTPS传输JWT
  • 防范XSS攻击(避免localStorage存储,推荐HttpOnly Cookie)
  • 定期轮换加密密钥
  • 实现令牌黑名单机制


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

相关文章:

  • ieee模版如何修改参考文献的格式以及多作者省略等
  • Docker 系列之 docker-compose 容器编排详解
  • C语言教程——文件处理(2)
  • C语言:结构体
  • DeepSeek-R1 低成本训练的根本原因是?
  • 全面认识了解DeepSeek+利用ollama在本地部署、使用和体验deepseek-r1大模型
  • 【RocketMQ】RocketMq之IndexFile深入研究
  • 机器学习day5
  • 【PDF提取局部内容改名】批量获取PDF局部文字内容改名 基于QT和百度云api的完整实现方案
  • 后盾人JS -- 原型
  • C语言教学第四课:控制结构
  • 内核定时器3-用户空间定时器
  • Docker Hub 镜像 Pull 失败的解决方案
  • AJAX笔记进阶篇
  • 《使用Ollama部署DeepSeek并进行对话全过程记录》
  • Spring 面试题【每日20道】【其二】
  • 11.1 LangChain Chains 最佳实践:从流水线设计到生产部署的全链路指南
  • 35.Word:公积金管理中心文员小谢【37】
  • string例题
  • MYSQL性能调优连接器、查询缓存、分析器、优化器、执行器、一图详解MYSQL底层工作原理
  • 泰山Office开源计划
  • 机试题——字符匹配
  • Python的那些事第十篇:隐藏细节与提供接口的艺术Python中的封装
  • Leetcode—598. 区间加法 II【简单】
  • golang命令大全7--性能优化与分析
  • Vue - readonly 与 shallowReadonly