位置:首页 > Java > Spring Security集成JWT实现无状态认证方案

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 可以实现无状态的身份验证和授权机制,在电商系统中常用于用户登录认证和权限管理。

在SpringSecurity中集成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 管理能力。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多