在现代应用开发中,用户认证和授权是至关重要的环节。本文将详细介绍如何使用 Spring Boot 3、Spring Security 6、JWT 和 Redis 实现一个安全高效的用户认证系统,包含一人一号认证和 Token 无感刷新功能。
🚨【阿里云限时特惠】云产品低至38元/年起!🎉
各位技术伙伴,阿里云爆款钜惠来袭!立即抢购:阿里云特惠 💰
🔥 新人专享特惠
-
200M带宽云服务器
38元/年起
(官网价¥459元/年),立省421元!
✔️ 适用场景:网站搭建/Web应用/电商独立站 -
经济型e实例
续费99元/年
| 2核2G + 3M带宽 + 40G ESSD云盘
✔️ 含防病毒版安全防护(防勒索/挖矿/木马)
✔️ 限新用户,每人限购1台
🤖 AI大模型特惠
-
DeepSeek R1大模型
首年99元起
| 1.5B/7B参数规格
✔️ 支持宝塔面板一键部署
✔️ 数学/代码/推理任务表现出色 -
企业知识库应用
数据库+文件存储+多端支持
✔️ 低代码扩展 + 钉钉/企微/微信集成
一、功能概述
- 一人一号认证:确保每个用户同一时间只能在一个设备登录,新设备登录会踢掉旧设备
- 无感刷新 Token:在用户 Token 过期时,自动刷新 Token 保持用户会话连续性
- 基于 JWT 和 Redis:使用 JWT 实现无状态认证,借助 Redis 存储用户登录状态和权限信息
二、技术栈
- Spring Boot 3.1.5
- Spring Security 6.2.1
- Redis 7.2.4
- JWT (Java JWT 库)
三、项目结构
src/main/java/
├── com/javastudy/demo/
│ ├── config/ # 配置类
│ ├── controller/ # 控制器
│ ├── service/ # 服务层
│ ├── util/ # 工具类
│ ├── model/ # 数据模型
│ └── filter/ # 过滤器
四、Maven 依赖
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Spring Boot Starter Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Java JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
五、核心配置
1. Redis 配置
spring:
redis:
host: localhost
port: 6379
password:
lettuce:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
security:
jwt:
secret: your-secret-key # JWT签名密钥
access-token-expiration: 30m # 访问令牌过期时间
refresh-token-expiration: 7d # 刷新令牌过期时间
2. Security 配置
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.example.demo.filter.JwtTokenFilter;
import com.example.demo.service.CustomUserDetailsService;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final JwtTokenFilter jwtTokenFilter;
private final CustomUserDetailsService userDetailsService;
public SecurityConfig(JwtTokenFilter jwtTokenFilter, CustomUserDetailsService userDetailsService) {
this.jwtTokenFilter = jwtTokenFilter;
this.userDetailsService = userDetailsService;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {