Spring Security集成JWT实现无状态认证方案
时间:2026-08-18 | 作者:宇宙开黑者 | 阅读:0在构建现代电商系统时,用户登录认证和权限管理是不可或缺的一环。
传统的基于 Session 的认证方式在分布式架构下显得力不从心,而 JSON Web Token(JWT) 凭借其无状态、轻量级的特点,逐渐成为开发者的首选方案。
今天,我们就来聊聊如何在 Spring Security 中集成 JWT,实现一套高效、安全的无状态认证机制。
1. Spring Security 集成 JWT 概述
JSON Web Token(JWT)是一种用于在网络应用间安全传递信息的开放标准(RFC 7519)。
Spring Security 集成 JWT 可以实现无状态的身份验证和授权机制,在电商系统中常用于用户登录认证和权限管理。
2. 搭建 JWT 认证工程
2.1 依赖添加
首先,在 pom.xml 中添加 Spring Security、Spring Boot Web、JJWT 等必要依赖。
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security io.jsonwebtoken jjwt 0.9.1 org.springframework.boot spring-boot-starter-data-redis
2.2 配置 Spring Security
接下来,创建 Spring Security 配置类。
这里主要用于配置认证规则和授权规则。
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.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/auth/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}
3. 使用 JWT 认证
3.1 生成 JWT
可以创建 JWT 工具类,用于生成和解析 JWT。
这一部分是整个认证流程的基础。
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import ja va.util.Date;
@Component
public class JwtUtils {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expirationMs}")
private int expirationMs;
public String generateJwtToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + expirationMs))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public String getUserNameFromJwtToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getSubject();
}
public boolean validateJwtToken(String authToken) {
try {
Jwts.parser().setSigningKey(secret).parseClaimsJws(authToken);
return true;
} catch (Exception e) {
return false;
}
}
}
3.2 认证过滤器
还需要创建 JWT 认证过滤器,用于拦截请求并验证 JWT。
当请求携带合法 Token 时,系统会将用户认证信息写入 SecurityContextHolder。
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import ja vax.servlet.FilterChain;
import ja vax.servlet.ServletException;
import ja vax.servlet.http.HttpServletRequest;
import ja vax.servlet.http.HttpServletResponse;
import ja va.io.IOException;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
String jwt = parseJwt(request);
if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
String username = jwtUtils.getUserNameFromJwtToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (ExpiredJwtException e) {
// 处理 JWT 过期异常
}
filterChain.doFilter(request, response);
}
private String parseJwt(HttpServletRequest request) {
String headerAuth = request.getHeader("Authorization");
if (headerAuth != null && headerAuth.startsWith("Bearer ")) {
return headerAuth.substring(7);
}
return null;
}
}
4. 使用 Redis 解决退出时 JWT 不能过期问题
4.1 Redis 配置和启动
JWT 无状态机制虽然轻量,但也带来一个常见问题:用户退出后,Token 在有效期内仍然可用。
为了解决这个问题,可以引入 Redis。
先在 application.properties 中配置 Redis 连接信息。
spring.redis.host=localhost spring.redis.port=6379
确保 Redis 服务已启动,也可以使用 Docker 快速启动 Redis 容器。
docker run -p 6379:6379 redis
4.2 将 JWT 放到 Redis 中
接着,创建 Redis 工具类,用于操作 Redis 存储 JWT。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import ja va.util.concurrent.TimeUnit;
@Component
public class RedisUtils {
@Autowired
private RedisTemplate redisTemplate;
public void set(String key, String value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
public boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
public void delete(String key) {
redisTemplate.delete(key);
}
}
4.3 解决退出问题
在用户退出时,可以将 JWT 存入 Redis 黑名单。
后续验证时,再检查 JWT 是否已经进入黑名单。
这样就能解决 JWT 退出不能过期的问题。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import ja va.util.concurrent.TimeUnit;
@RestController
public class AuthController {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private RedisUtils redisUtils;
@PostMapping("/api/auth/logout")
public String logout(@RequestHeader("Authorization") String authorizationHeader) {
String jwt = authorizationHeader.substring(7);
long expiration = jwtUtils.getExpirationDateFromJwtToken(jwt).getTime() - System.currentTimeMillis();
redisUtils.set(jwt, "blacklisted", expiration, TimeUnit.MILLISECONDS);
return "Logged out successfully";
}
}
5. 示例总结
- 工程搭建:添加必要依赖,配置 Spring Security 实现基本的认证和授权规则。
- JWT 认证:使用 JJWT 库生成和解析 JWT,创建认证过滤器拦截请求并验证 JWT。
- Redis 集成:配置 Redis 连接信息,使用 Redis 存储 JWT 黑名单,解决 JWT 退出不能过期的问题。
整体来看,Spring Security 与 JWT 的结合,可以帮助电商系统实现更高效的无状态认证。
如果再配合 Redis 黑名单机制,就能够进一步完善退出场景下的 Token 管理能力。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- Java异常处理实战:从体系架构到健壮性设计全解
- 时间:2026-08-27
-
- 基于Spring Security实现自动登录的完整指南
- 时间:2026-08-27
-
- VS Code Java开发高效配置清单(可直接复制使用)
- 时间:2026-08-27
-
- JavaSwing实现自定义TablePanel组件(附完整代码)
- 时间:2026-08-27
-
- Java基础攻略:输入输出、方法与数组实战指南
- 时间:2026-08-27
-
- Java反射、枚举、Lambda表达式及泛型通配符实例详解
- 时间:2026-08-27
-
- 30个经典算法题及Java解答(含实例代码)
- 时间:2026-08-27
-
- Spring Data JPA 查询实战:方法命名与 @Query 注解详解
- 时间:2026-08-27
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15
