在现代 Web 应用中,用户认证和授权是保障系统安全的核心环节。传统的 Session 认证方式在分布式系统或前后端分离场景下存在局限,而 JWT(JSON Web Token)作为一种无状态的认证机制,凭借其轻量、可扩展和跨服务的特性,成为主流选择。Spring Boot 3.4.3 结合 Spring Security 6.4.2 和 JWT,可以实现高效、安全的用户登录认证。本文将详细介绍如何在 Spring Boot 3.4.3 中集成 Spring Security 和 JWT,实现用户登录功能,并附上完整代码示例,助你在2025年的项目中快速落地认证方案。
1. JWT 和 Spring Security 简介
1.1 什么是 JWT?
JWT 是一种基于 JSON 的开放标准(RFC 7519),用于在各方之间安全传输信息。它由三部分组成:Header(头)、Payload(负载)和 Signature(签名),通过.分隔。JWT 的无状态特性使其非常适合分布式系统。
1.2 Spring Security 的作用
Spring Security 是 Spring 生态中的安全框架,提供认证、授权和防护功能。Spring Security 6.4.2 支持 Lambda 风格的配置,与 Spring Boot 3.4.3 无缝集成。
1.3 本文目标
- 配置 Spring Security 和 JWT。
- 实现用户登录并生成 Token。
- 验证 Token 并保护接口。
2. 项目实战
以下是基于 Spring Boot 3.4.3 和 Spring Security 6.4.2 结合 JWT 实现用户登录的完整步骤。
2.1 添加 Maven 依赖
在 pom.xml 中添加必要的依赖:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
</parent>
<groupId>cn.itbeien</groupId>
<artifactId>springboot-jwt</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.5</version>
</dependency>
</dependencies>
</project>
说明:
spring-boot-starter-security:提供 Spring Security 支持。jjwt-*:JWT 的核心库。
2.2 配置 JWT 工具类
创建一个工具类生成和验证 JWT:
java
package cn.itbeien.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.util.Date;
public class JwtUtil {
private static final String SECRET_KEY = "your-256-bit-secret-key-here-1234567890"; // 至少 256 位
private static final long EXPIRATION_TIME = 1000 * 60 * 60; // 1小时
private static SecretKey getSecretKey() {
return Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
}
public static String generateToken(String username) {
return Jwts.builder()
.subject(username)
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(getSecretKey())
.compact();
}
public static String getUsernameFromToken(String token) {
Claims claims = Jwts.parser()
.verifyWith(getSecretKey())
.build()
.parseSignedClaims(token)
.getPayload();
return claims.getSubject();
}
public static boolean validateToken(String token) {
try {
Jwts.parser().verifyWith(getSecretKey()).build().parseSignedClaims(token);
return true;
} catch (Exception e) {
return false;
}
}
}
说明:
SECRET_KEY:用于签名,需足够长且安全。generateToken:生成 JWT。getUsernameFromToken和validateToken:解析和验证 Token。
2.3 配置 Spring Security
创建一个 Security 配置类:
java
package cn.itbeien.config;
import cn.itbeien.filter.JwtAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // 禁用 CSRF
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 无状态
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/login").permitAll() // 登录接口公开
.anyRequest().authenticated() // 其他请求需认证
)
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); // 添加 JWT 过滤器
return http.build();
}
}
2.4 创建 JWT 过滤器
实现 Token 验证逻辑:
java
package cn.itbeien.filter;
import cn.itbeien.util.JwtUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
if (JwtUtil.validateToken(token)) {
String username = JwtUtil.getUsernameFromToken(token);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, null);
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
chain.doFilter(request, response);
}
}
2.5 创建用户服务
模拟用户认证逻辑:
java
package cn.itbeien.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public boolean authenticate(String username, String password) {
// 模拟数据库验证
return "admin".equals(username) && "123456".equals(password);
}
}
2.6 创建登录控制器
实现登录并返回 JWT:
java
package cn.itbeien.controller;
import cn.itbeien.service.UserService;
import cn.itbeien.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class LoginController {
@Autowired
private UserService userService;
@PostMapping("/login")
public ResponseEntity<String> login(@RequestParam String username, @RequestParam String password) {
if (userService.authenticate(username, password)) {
String token = JwtUtil.generateToken(username);
return ResponseEntity.ok(token);
}
return ResponseEntity.status(401).body("登录失败");
}
@PostMapping("/protected")
public String protectedEndpoint() {
return "这是一个受保护的接口";
}
}
2.7 启动与测试
- 启动 Spring Boot 应用。
- 测试登录:
POST http://localhost:8080/api/login?username=admin&password=123456- 成功返回 JWT Token。
- 测试受保护接口:
- 请求
POST http://localhost:8080/api/protected,Header 中添加Authorization: Bearer <token>。 - 未携带 Token 或 Token 无效,返回 403。
- 请求
3. 进阶功能(可选)
-
自定义权限
为用户添加角色:
javaList<SimpleGrantedAuthority> authorities = List.of(new SimpleGrantedAuthority("ROLE_USER")); UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, authorities); -
Token 刷新
添加刷新 Token 接口:
java@PostMapping("/refresh") public ResponseEntity<String> refreshToken(@RequestHeader("Authorization") String token) { if (JwtUtil.validateToken(token)) { String username = JwtUtil.getUsernameFromToken(token); return ResponseEntity.ok(JwtUtil.generateToken(username)); } return ResponseEntity.status(401).body("无效 Token"); } -
数据库集成
使用 MySQL 存储用户信息(结合 MyBatis 或 JPA)。
4. 总结
Spring Boot 3.4.3 和 Spring Security 6.4.2 结合 JWT,提供了一种现代化、无状态的用户认证方案。本文从依赖配置到登录实现,覆盖了核心步骤。