在Spring Security中集成JWT实现无状态认证

 更新时间:2026年08月05日 09:15:19   作者:1加1等于  
Spring Security 集成 JWT 可以实现无状态的身份验证和授权机制,在电商系统中常用于用户登录认证和权限管理,本文手把手教你搭建JWT认证工程,用Redis黑名单解决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 等必要依赖。

<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>
    <!-- JJWT -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
    <!-- Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

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 java.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。

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 javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.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 配置和启动

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 java.util.concurrent.TimeUnit;

@Component
public class RedisUtils {

    @Autowired
    private RedisTemplate<String, String> 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 是否在黑名单中。

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 java.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实现无状态认证的详细内容,更多关于Spring Security集成JWT无状态认证的资料请关注脚本之家其它相关文章!

相关文章

  • Java利用朴素贝叶斯分类算法实现信息分类

    Java利用朴素贝叶斯分类算法实现信息分类

    贝叶斯分类算法是统计学的一种分类方法,它是一类利用概率统计知识进行分类的算法。本文将利用朴素贝叶斯分类算法实现信息分类,需要的可以参考一下
    2022-06-06
  • SpringBoot实现多数据源的实战案例

    SpringBoot实现多数据源的实战案例

    这篇文章主要介绍了SpringBoot实现多数据源的实战案例,文中通过示例代码和图文展示介绍的非常详细,对大家的学习或工作有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2024-01-01
  • 一文搞懂Java中的线程安全与线程同步

    一文搞懂Java中的线程安全与线程同步

    线程安全指在被多个线程访问时,程序可以持续进行正确的处理。线程同步是指程序中用于控制不同线程间操作发生相对顺序的机制。本文将通过示例详细为大家讲讲二者的使用,需要的可以参考一下
    2022-06-06
  • MyBatis中map的应用与模糊查询实现代码

    MyBatis中map的应用与模糊查询实现代码

    这篇文章主要介绍了MyBatis中map的应用与模糊查询实现代码,文中通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-11-11
  • Java解决LocalDateTime传输前端为时间的数组

    Java解决LocalDateTime传输前端为时间的数组

    本文主要介绍了Java解决LocalDateTime传输前端为时间的数组,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-03-03
  • Java之Spring简单的读取和存储对象

    Java之Spring简单的读取和存储对象

    这篇文章主要介绍了Spring的读取和存储对象,获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注⼊,想进一步了解的同学可以参考本文
    2023-04-04
  • java使用多线程找出最大随机数

    java使用多线程找出最大随机数

    这篇文章主要为大家详细介绍了java使用多线程找出最大随机数,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • java.lang.NumberFormatException异常解决方案详解

    java.lang.NumberFormatException异常解决方案详解

    这篇文章主要介绍了java.lang.NumberFormatException异常解决方案详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • SpringBoot java-jar命令行启动原理解析

    SpringBoot java-jar命令行启动原理解析

    这篇文章主要介绍了SpringBoot java-jar命令行启动原理解析,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • Spring security实现对账户进行加密

    Spring security实现对账户进行加密

    这篇文章主要介绍了Spring security实现对账户进行加密,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03

最新评论