Spring Boot 和 Spring Security 实现 JWT 认证

一、 JWT(JSON Web Token)

1.JWT 基本概念

JWT 是一种开放标准(RFC 7519),用于在网络应用间安全传递 JSON 格式的声明信息。其核心特点包括:

  1. 紧凑性:通过 Base64URL 编码生成字符串,可通过 URL、HTTP Header 或 POST 参数传输。
  2. 自包含:负载(Payload)直接携带用户信息(如 ID、角色),减少服务端查询数据库的开销。
  3. 数字签名:使用密钥(HMAC)或公钥/私钥(RSA)签名,确保信息未被篡改。
2.JWT 结构

JWT 由三部分组成,以点号 . 分隔:Header.Payload.Signature

  1. Header(头部)

    • 描述令牌类型(typ: "JWT")和签名算法(如 alg: HS256),Base64URL 编码后形成第一部分。
    json 复制代码
    { "alg": "HS256", "typ": "JWT" }
  2. Payload(负载)

    • 存储声明(Claims),包含用户数据及标准声明(如 sub 用户 ID、exp 过期时间)。
    • 声明类型
      • 注册声明 (可选):预定义字段(iss 签发者、aud 受众)。
      • 公共声明 :自定义字段(如 name: "John")。
      • 私有声明:系统内部使用的自定义字段。

    注意 :Payload 仅 Base64URL 编码,未加密,避免存储敏感信息(如密码)。

  3. Signature(签名)

    • 对编码后的 Header 和 Payload 用指定算法(如 HMAC-SHA256)签名,密钥由服务端保管:
    js 复制代码
    HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
    • 签名验证数据完整性和来源真实性。
3.JWT 工作原理
  1. 认证阶段
    • 用户提交凭证(用户名/密码)→ 服务端验证通过 → 生成 JWT 返回客户端。
  2. 客户端存储
    • 客户端将 JWT 存入 localStoragesessionStorage 或 Cookie(建议 HttpOnly 防 XSS)。
  3. 请求携带
    • 后续请求在 HTTP Header 中添加:Authorization: Bearer <JWT>
  4. 服务端验证
    • 校验签名有效性、过期时间(exp)及受众(aud)→ 通过则允许访问资源。
4.JWT vs Session 认证
特性 JWT Session
服务端状态 无状态(信息在 Token 中) 需存储会话信息(内存/数据库)
扩展性 天然支持分布式系统 需 Session 共享机制(如 Redis)
安全性 签名防篡改;但需防 XSS 盗取 Token 依赖 Cookie;易受 CSRF 攻击
性能 减少数据库查询;但 Token 体积较大 需频繁查询会话数据

JWT 在微服务、跨域单点登录(SSO)场景中优势显著。


5.应用场景
  1. 身份认证:用户登录后,JWT 作为无状态凭证。
  2. 单点登录(SSO):一次登录生成 JWT,多系统共享认证状态。

二、Spring Security 集成 JWT

  1. 认证流程

    • 用户登录:客户端提交凭证 → 服务端验证并生成 JWT
    • 请求携带 :客户端在 Authorization: Bearer <token> 头中附加 JWT
    • 服务端验证:Spring Security 过滤器链解析并验证 JWT 有效性
  2. 技术优势

    • 无状态架构:服务端无需存储会话,适合微服务分布式系统
    • 细粒度授权:通过 JWT Claims 实现角色/权限动态控制
1.JWT 配置参数
yaml 复制代码
jwt:
  secret: "base64-encoded-secret"  # Base64 编码密钥
  expiration: 86400000             # Token 有效期(24小时)
  header: Authorization             # 请求头字段
2.Spring Security 配置
java 复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()          // 关闭 CSRF
            .authorizeRequests()
            .antMatchers("/api/auth/**").permitAll()  // 放行登录接口
            .anyRequest().authenticated()             // 其他接口需认证
            .and()
            .addFilterBefore(jwtAuthFilter(), UsernamePasswordAuthenticationFilter.class); // 添加 JWT 过滤器
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 密码加密器
    }
}
3.JWT 工具类实现
java 复制代码
@Component
public class JwtUtils {
    @Value("${jwt.secret}")
    private String secret;

    public String generateToken(UserDetails userDetails) {
        return Jwts.builder()
            .setSubject(userDetails.getUsername())   // 用户名作为主体
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + expiration))
            .signWith(SignatureAlgorithm.HS512, secret) // HS512 算法签名
            .compact();
    }

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

签名算法选择

算法类型 适用场景
HS256/HS512 单应用场景(对称加密)
RS256/RS512 多服务调用(非对称加密)

4.认证流程实现
(1)登录接口生成 Token
java 复制代码
@RestController
@RequestMapping("/api/auth")
public class AuthController {
    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody LoginRequest request) {
        // 1. 验证用户名密码
        UserDetails user = userDetailsService.loadUserByUsername(request.getUsername());
        // 调用passwordEncoder验证密码是否一致
        if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
            return ResponseEntity.status(401).build();
        }
        // 2. 生成 JWT
        String token = jwtUtils.generateToken(user);
        return ResponseEntity.ok(token);
    }
}

新增用户时使用PasswordEncoder加密密码。

(2)JWT 认证过滤器
java 复制代码
public class JwtAuthFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith("Bearer ")) {
            chain.doFilter(request, response); // 放行未认证请求
            return;
        }
        String token = header.substring(7);
        Claims claims = jwtUtils.parseToken(token); // 解析 Token
        // 构建 Authentication 对象并存入 SecurityContext
        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
            claims.getSubject(), null, AuthorityUtils.createAuthorityList("ROLE_USER")
        );
        SecurityContextHolder.getContext().setAuthentication(auth);
        chain.doFilter(request, response);
    }
}

在 Spring Security 中,UsernamePasswordAuthenticationToken 的 authorities 参数用于注入当前用户的​​权限集合​​(Collection<? extends GrantedAuthority>)。

6.常见问题与解决方案
(1)Token 失效场景
  • 签名不匹配:检查密钥一致性(确保 Base64 编码正确)
  • 过期时间(exp)未生效:服务器时间不同步 → 使用 NTP 同步
(2)跨域问题(CORS)
java 复制代码
@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    config.addAllowedOrigin("https://your-frontend.com");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}
相关推荐
sg_knight43 分钟前
Spring Cloud LoadBalancer深度解析:官方负载均衡方案迁移指南与避坑实践
java·spring boot·spring·spring cloud·微服务·负载均衡
network_tester1 小时前
路由器压测实战:从负载均衡到DDoS防御,5步定位性能瓶颈(附脚本工具包)
网络·网络协议·tcp/ip·http·网络安全·https·信息与通信
llwszx1 小时前
Spring Boot 整合 Spring AI 与 MCP 开发智能体工具指南
人工智能·spring boot·spring·智能体·spring ai·mcp
稳联技术1 小时前
生物制药自动化升级:Modbus TCP与Ethernet/IP协议转换实践
网络·tcp/ip·自动化
_何同学1 小时前
Ollama 安装 DeepSeek 与 Spring Boot 集成指南
java·spring boot·后端·ai
weixin_442643422 小时前
IP Guard vs Ping32:2025 年企业防泄密系统深度横评
服务器·网络·安全·数据安全
mall_09053 小时前
Spring Cloud使用Eureka调用接口,超时设置(三)
spring·spring cloud·eureka
企鹅侠客3 小时前
长连接、短连接、WebSocket区别和使用场景
网络·websocket·网络协议
CLOUD ACE4 小时前
谷歌云代理 | 金融合规上云:谷歌云PCI DSS认证环境搭建指南
服务器·网络·金融
草履虫建模4 小时前
Web开发全栈流程 - Spring boot +Vue 前后端分离
java·前端·vue.js·spring boot·阿里云·elementui·mybatis