From a174cb255f0326e701350a5edd5e0a0b272e6ea9 Mon Sep 17 00:00:00 2001
From: panxuejie <15855548138@163.com>
Date: Fri, 9 Jan 2026 10:21:28 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9redis=E7=9A=84=E7=BC=93?=
=?UTF-8?q?=E5=AD=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
common/common-core/pom.xml | 7 ++
.../tacit/common/constant/CommonConstant.java | 4 +
.../com/tacit/common/utils/SecurityUtils.java | 89 +++++++++++++++++++
.../com/tacit/common/utils/JwtUtilsTest.java | 2 -
common/common-feign/pom.xml | 6 ++
.../feign/config/FeignClientConfig.java | 2 +-
.../feign/config/FeignGlobalConfig.java | 9 +-
.../FeignAuthInterceptor.java | 2 +-
...ot.autoconfigure.AutoConfiguration.imports | 1 +
common/common-redis/pom.xml | 5 ++
.../common/redis/config/RedisConfig.java | 25 +++---
.../tacit/common/redis/utils/RedisUtils.java | 7 +-
.../main/resources/META-INF/spring.factories | 1 -
...ot.autoconfigure.AutoConfiguration.imports | 1 +
.../xxljob/XxlJobAutoConfiguration.java | 5 ++
.../main/resources/META-INF/spring.factories | 2 -
...ot.autoconfigure.AutoConfiguration.imports | 0
.../com/tacit/admin/AdminApplication.java | 4 -
.../tacit/admin/config/SecurityConfig.java | 54 ++++++++---
.../admin/controller/AuthController.java | 24 ++---
.../com/tacit/admin/service/UserService.java | 6 ++
.../admin/service/impl/UserServiceImpl.java | 24 ++++-
.../java/com/tacit/app/AppApiApplication.java | 1 -
.../tacit/app/config/AppSecurityConfig.java | 24 +++--
tacit-gateway/pom.xml | 6 --
.../com/tacit/gateway/GatewayApplication.java | 1 -
.../filter/JwtAuthenticationFilter.java | 26 +++---
27 files changed, 256 insertions(+), 82 deletions(-)
rename common/{common-model => common-core}/src/main/java/com/tacit/common/constant/CommonConstant.java (88%)
create mode 100644 common/common-core/src/main/java/com/tacit/common/utils/SecurityUtils.java
rename common/common-feign/src/main/java/com/tacit/common/feign/{ => interceptor}/FeignAuthInterceptor.java (98%)
create mode 100644 common/common-feign/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
delete mode 100644 common/common-redis/src/main/resources/META-INF/spring.factories
create mode 100644 common/common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
delete mode 100644 common/common-xxl-job/src/main/resources/META-INF/spring.factories
create mode 100644 common/common-xxl-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
diff --git a/common/common-core/pom.xml b/common/common-core/pom.xml
index 257124d..bbd54d5 100644
--- a/common/common-core/pom.xml
+++ b/common/common-core/pom.xml
@@ -49,6 +49,13 @@
org.apache.commons
commons-lang3
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+ provided
+
diff --git a/common/common-model/src/main/java/com/tacit/common/constant/CommonConstant.java b/common/common-core/src/main/java/com/tacit/common/constant/CommonConstant.java
similarity index 88%
rename from common/common-model/src/main/java/com/tacit/common/constant/CommonConstant.java
rename to common/common-core/src/main/java/com/tacit/common/constant/CommonConstant.java
index 1eb5d89..a600e14 100644
--- a/common/common-model/src/main/java/com/tacit/common/constant/CommonConstant.java
+++ b/common/common-core/src/main/java/com/tacit/common/constant/CommonConstant.java
@@ -26,5 +26,9 @@ public class CommonConstant {
public static final String ROLE_USER = "user";
// Redis key
+ public static final String REDIS_KEY_TACIT = "tacit:";
+
public static final String REDIS_KEY_USER_TOKEN = "user:token:";
+
+ public static final String REDIS_KEY_TACIT_USER_TOKEN = "tacit:user:token:";
}
\ No newline at end of file
diff --git a/common/common-core/src/main/java/com/tacit/common/utils/SecurityUtils.java b/common/common-core/src/main/java/com/tacit/common/utils/SecurityUtils.java
new file mode 100644
index 0000000..e381c4c
--- /dev/null
+++ b/common/common-core/src/main/java/com/tacit/common/utils/SecurityUtils.java
@@ -0,0 +1,89 @@
+package com.tacit.common.utils;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+/**
+ * Security工具类,提供获取当前用户信息的方法
+ * @author lidongjin
+ * @date 2026-01-09
+ */
+public class SecurityUtils {
+
+ /**
+ * 从当前认证上下文获取用户ID
+ * @return 用户ID
+ */
+ public static Long getCurrentUserId() {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication == null) {
+ return null;
+ }
+
+ // 获取认证对象的details,这里存储了userId等信息
+ Object details = authentication.getDetails();
+ if (details == null || !(details instanceof java.util.Map)) {
+ return null;
+ }
+
+ // 从map中获取userId
+ java.util.Map, ?> userDetails = (java.util.Map, ?>) details;
+ Object userIdObj = userDetails.get("userId");
+ if (userIdObj == null) {
+ return null;
+ }
+
+ if (userIdObj instanceof Long) {
+ return (Long) userIdObj;
+ }
+
+ if (userIdObj instanceof Integer) {
+ return ((Integer) userIdObj).longValue();
+ }
+
+ return Long.parseLong(userIdObj.toString());
+ }
+
+ /**
+ * 从当前认证上下文获取用户名
+ * @return 用户名
+ */
+ public static String getCurrentUsername() {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication == null) {
+ return null;
+ }
+
+ Object principal = authentication.getPrincipal();
+ if (principal == null || !(principal instanceof User)) {
+ return null;
+ }
+
+ return ((User) principal).getUsername();
+ }
+
+ /**
+ * 从当前认证上下文获取用户角色
+ * @return 用户角色
+ */
+ public static String getCurrentUserRole() {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication == null) {
+ return null;
+ }
+
+ // 获取第一个角色
+ return authentication.getAuthorities().stream()
+ .findFirst()
+ .map(grantedAuthority -> {
+ String role = grantedAuthority.getAuthority();
+ // 移除ROLE_前缀
+ if (role.startsWith("ROLE_")) {
+ return role.substring(5);
+ }
+ return role;
+ })
+ .orElse(null);
+ }
+}
diff --git a/common/common-core/src/test/java/com/tacit/common/utils/JwtUtilsTest.java b/common/common-core/src/test/java/com/tacit/common/utils/JwtUtilsTest.java
index 4b953d6..a4517b2 100644
--- a/common/common-core/src/test/java/com/tacit/common/utils/JwtUtilsTest.java
+++ b/common/common-core/src/test/java/com/tacit/common/utils/JwtUtilsTest.java
@@ -1,7 +1,5 @@
package com.tacit.common.utils;
-import com.tacit.common.constant.CommonConstant;
-import io.jsonwebtoken.Claims;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
diff --git a/common/common-feign/pom.xml b/common/common-feign/pom.xml
index fd0d945..4865db9 100644
--- a/common/common-feign/pom.xml
+++ b/common/common-feign/pom.xml
@@ -22,6 +22,12 @@
${project.parent.version}
+
+ com.tacit
+ common-core
+ ${project.parent.version}
+
+
com.alibaba.cloud
diff --git a/common/common-feign/src/main/java/com/tacit/common/feign/config/FeignClientConfig.java b/common/common-feign/src/main/java/com/tacit/common/feign/config/FeignClientConfig.java
index 50f6f51..7062c19 100644
--- a/common/common-feign/src/main/java/com/tacit/common/feign/config/FeignClientConfig.java
+++ b/common/common-feign/src/main/java/com/tacit/common/feign/config/FeignClientConfig.java
@@ -1,6 +1,6 @@
package com.tacit.common.feign.config;
-import com.tacit.common.feign.FeignAuthInterceptor;
+import com.tacit.common.feign.interceptor.FeignAuthInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
diff --git a/common/common-feign/src/main/java/com/tacit/common/feign/config/FeignGlobalConfig.java b/common/common-feign/src/main/java/com/tacit/common/feign/config/FeignGlobalConfig.java
index 74c3b10..6724b58 100644
--- a/common/common-feign/src/main/java/com/tacit/common/feign/config/FeignGlobalConfig.java
+++ b/common/common-feign/src/main/java/com/tacit/common/feign/config/FeignGlobalConfig.java
@@ -1,13 +1,16 @@
package com.tacit.common.feign.config;
-import org.springframework.context.annotation.Configuration;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* Feign全局配置类,设置默认Feign客户端配置
* 所有@FeignClient会自动应用此配置,无需显式指定
*/
-@Configuration
-@EnableFeignClients(defaultConfiguration = FeignClientConfig.class)
+@AutoConfiguration
+@EnableFeignClients(
+ basePackages = "com.tacit.common.feign",
+ defaultConfiguration = FeignClientConfig.class
+)
public class FeignGlobalConfig {
}
\ No newline at end of file
diff --git a/common/common-feign/src/main/java/com/tacit/common/feign/FeignAuthInterceptor.java b/common/common-feign/src/main/java/com/tacit/common/feign/interceptor/FeignAuthInterceptor.java
similarity index 98%
rename from common/common-feign/src/main/java/com/tacit/common/feign/FeignAuthInterceptor.java
rename to common/common-feign/src/main/java/com/tacit/common/feign/interceptor/FeignAuthInterceptor.java
index 6a1c722..29c4865 100644
--- a/common/common-feign/src/main/java/com/tacit/common/feign/FeignAuthInterceptor.java
+++ b/common/common-feign/src/main/java/com/tacit/common/feign/interceptor/FeignAuthInterceptor.java
@@ -1,4 +1,4 @@
-package com.tacit.common.feign;
+package com.tacit.common.feign.interceptor;
import com.tacit.common.constant.CommonConstant;
import lombok.extern.slf4j.Slf4j;
diff --git a/common/common-feign/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/common/common-feign/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..99cc335
--- /dev/null
+++ b/common/common-feign/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.tacit.common.feign.config.FeignGlobalConfig
diff --git a/common/common-redis/pom.xml b/common/common-redis/pom.xml
index cd90fa7..7c45f67 100644
--- a/common/common-redis/pom.xml
+++ b/common/common-redis/pom.xml
@@ -20,6 +20,11 @@
org.springframework.boot
spring-boot-starter-data-redis
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
diff --git a/common/common-redis/src/main/java/com/tacit/common/redis/config/RedisConfig.java b/common/common-redis/src/main/java/com/tacit/common/redis/config/RedisConfig.java
index 6931b3a..775e62c 100644
--- a/common/common-redis/src/main/java/com/tacit/common/redis/config/RedisConfig.java
+++ b/common/common-redis/src/main/java/com/tacit/common/redis/config/RedisConfig.java
@@ -5,21 +5,25 @@ import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.tacit.common.redis.utils.RedisUtils;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
-@Configuration
-@ComponentScan(basePackages = "com.tacit.common.redis.utils")
+@AutoConfiguration
+@ConditionalOnClass(RedisConnectionFactory.class)
+@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {
-
+
@Bean
- public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
+ public RedisTemplate stringObjectRedisTemplate(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate<>();
template.setConnectionFactory(factory);
@@ -51,9 +55,8 @@ public class RedisConfig {
}
@Bean
- public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
- StringRedisTemplate template = new StringRedisTemplate();
- template.setConnectionFactory(factory);
- return template;
+ @ConditionalOnMissingBean
+ public RedisUtils redisUtils() {
+ return new RedisUtils();
}
}
\ No newline at end of file
diff --git a/common/common-redis/src/main/java/com/tacit/common/redis/utils/RedisUtils.java b/common/common-redis/src/main/java/com/tacit/common/redis/utils/RedisUtils.java
index d1586dd..1eb79d5 100644
--- a/common/common-redis/src/main/java/com/tacit/common/redis/utils/RedisUtils.java
+++ b/common/common-redis/src/main/java/com/tacit/common/redis/utils/RedisUtils.java
@@ -2,9 +2,9 @@ package com.tacit.common.redis.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@@ -18,9 +18,10 @@ import java.util.concurrent.TimeUnit;
* @CreateTime: 2026-01-07 09:27
*/
@Slf4j
-@Component
public class RedisUtils {
+
@Autowired
+ @Qualifier("stringObjectRedisTemplate")
private RedisTemplate redisTemplate;
@Autowired
@@ -345,7 +346,7 @@ public class RedisUtils {
/**
* 删除键
- * @param key 键(可以多个)
+ * @param keys 键(可以多个)
*/
public void delete(String... keys) {
if (keys != null && keys.length > 0) {
diff --git a/common/common-redis/src/main/resources/META-INF/spring.factories b/common/common-redis/src/main/resources/META-INF/spring.factories
deleted file mode 100644
index 55b9302..0000000
--- a/common/common-redis/src/main/resources/META-INF/spring.factories
+++ /dev/null
@@ -1 +0,0 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.tacit.common.redis.config.RedisConfig
\ No newline at end of file
diff --git a/common/common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/common/common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..05ec75e
--- /dev/null
+++ b/common/common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.tacit.common.redis.config.RedisConfig
\ No newline at end of file
diff --git a/common/common-xxl-job/src/main/java/com/tacit/common/xxljob/XxlJobAutoConfiguration.java b/common/common-xxl-job/src/main/java/com/tacit/common/xxljob/XxlJobAutoConfiguration.java
index 630a141..ab50701 100644
--- a/common/common-xxl-job/src/main/java/com/tacit/common/xxljob/XxlJobAutoConfiguration.java
+++ b/common/common-xxl-job/src/main/java/com/tacit/common/xxljob/XxlJobAutoConfiguration.java
@@ -20,7 +20,12 @@ import java.util.stream.Collectors;
* @Description: com.tacit.starter.xxljob
* @version: 1.0
*/
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+
+@AutoConfiguration
@EnableConfigurationProperties(XxlJobProperties.class)
+@ConditionalOnClass(XxlJobSpringExecutor.class)
public class XxlJobAutoConfiguration {
private Logger log = LoggerFactory.getLogger(XxlJobAutoConfiguration.class);
diff --git a/common/common-xxl-job/src/main/resources/META-INF/spring.factories b/common/common-xxl-job/src/main/resources/META-INF/spring.factories
deleted file mode 100644
index f2e205b..0000000
--- a/common/common-xxl-job/src/main/resources/META-INF/spring.factories
+++ /dev/null
@@ -1,2 +0,0 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.tacit.common.xxljob.XxlJobAutoConfiguration
\ No newline at end of file
diff --git a/common/common-xxl-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/common/common-xxl-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..e69de29
diff --git a/tacit-admin/src/main/java/com/tacit/admin/AdminApplication.java b/tacit-admin/src/main/java/com/tacit/admin/AdminApplication.java
index a0a7f55..5ecb78b 100644
--- a/tacit-admin/src/main/java/com/tacit/admin/AdminApplication.java
+++ b/tacit-admin/src/main/java/com/tacit/admin/AdminApplication.java
@@ -1,18 +1,14 @@
package com.tacit.admin;
-import com.tacit.common.redis.config.RedisConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
-import org.springframework.context.annotation.Import;
@SpringBootApplication
-@Import(RedisConfig.class)
@MapperScan("com.tacit.admin.mapper")
@EnableDiscoveryClient
-@EnableFeignClients(basePackages = "com.tacit.common.feign")
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
diff --git a/tacit-admin/src/main/java/com/tacit/admin/config/SecurityConfig.java b/tacit-admin/src/main/java/com/tacit/admin/config/SecurityConfig.java
index b570025..339f070 100644
--- a/tacit-admin/src/main/java/com/tacit/admin/config/SecurityConfig.java
+++ b/tacit-admin/src/main/java/com/tacit/admin/config/SecurityConfig.java
@@ -19,6 +19,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
@@ -27,6 +28,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
+import java.util.HashMap;
@Configuration
@EnableWebSecurity
@@ -44,11 +46,10 @@ public class SecurityConfig {
.cors(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
- .requestMatchers("/auth/**","test/**", "/test/hello", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
+ .requestMatchers("/auth/login", "/auth/register","test/**", "/test/hello", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
.requestMatchers("/test/feign/**").authenticated()
- .anyRequest().authenticated()
- )
- .addFilterBefore(authenticationFilter(), org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.class);
+ .anyRequest().authenticated())
+ .addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@@ -63,30 +64,55 @@ public class SecurityConfig {
if (authorization != null && authorization.startsWith(CommonConstant.JWT_PREFIX)) {
String token = authorization.substring(CommonConstant.JWT_PREFIX.length());
try {
- // 验证JWT令牌和Redis中的令牌是否存在
- if (JwtUtils.validateToken(token) && redisUtils.hasKey(token)) {
+ // 验证JWT令牌
+ if (JwtUtils.validateToken(token)) {
// 从令牌中获取用户信息
- String username = JwtUtils.getUsernameFromToken(token);
- String role = JwtUtils.getRoleFromToken(token);
+ Long userId = JwtUtils.getUserIdFromToken(token);
- // 创建认证对象
- User principal = new User(username, "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role.toUpperCase())));
- var authentication = new UsernamePasswordAuthenticationToken(principal, null, principal.getAuthorities());
- SecurityContextHolder.getContext().setAuthentication(authentication);
+ // 构建Redis key:tacit:user:token:{userId}
+ String redisKey = CommonConstant.REDIS_KEY_TACIT_USER_TOKEN + userId;
+
+ // 验证Redis中的令牌是否存在且匹配
+ String redisToken = redisUtils.get(redisKey);
+ if (token.equals(redisToken)) {
+ String username = JwtUtils.getUsernameFromToken(token);
+ String role = JwtUtils.getRoleFromToken(token);
+
+ // 创建认证对象
+ User principal = new User(username, "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role.toUpperCase())));
+
+ // 创建用户详情map,存储userId等信息
+ HashMap userDetails = new HashMap<>();
+ userDetails.put("userId", userId);
+ userDetails.put("username", username);
+ userDetails.put("role", role);
+
+ var authentication = new UsernamePasswordAuthenticationToken(principal, null, principal.getAuthorities());
+ authentication.setDetails(userDetails);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
}
} catch (Exception e) {
log.error("JWT令牌验证失败: {}", e.getMessage());
}
} else {
// 检查是否有用户上下文头(网关转发时添加)
- String userId = request.getHeader("X-User-Id");
+ String userIdStr = request.getHeader("X-User-Id");
String username = request.getHeader("X-Username");
String role = request.getHeader("X-Role");
- if (userId != null && username != null && role != null) {
+ if (userIdStr != null && username != null && role != null) {
// 创建认证对象
User principal = new User(username, "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role.toUpperCase())));
+
+ // 创建用户详情map,存储userId等信息
+ HashMap userDetails = new HashMap<>();
+ userDetails.put("userId", Long.parseLong(userIdStr));
+ userDetails.put("username", username);
+ userDetails.put("role", role);
+
var authentication = new UsernamePasswordAuthenticationToken(principal, null, principal.getAuthorities());
+ authentication.setDetails(userDetails);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
diff --git a/tacit-admin/src/main/java/com/tacit/admin/controller/AuthController.java b/tacit-admin/src/main/java/com/tacit/admin/controller/AuthController.java
index 9e06be2..701ee41 100644
--- a/tacit-admin/src/main/java/com/tacit/admin/controller/AuthController.java
+++ b/tacit-admin/src/main/java/com/tacit/admin/controller/AuthController.java
@@ -4,17 +4,16 @@ import com.tacit.admin.entity.dto.LoginRequest;
import com.tacit.admin.entity.dto.LoginResponse;
import com.tacit.admin.entity.dto.RegisterRequest;
import com.tacit.admin.service.UserService;
-import com.tacit.common.constant.CommonConstant;
import com.tacit.common.entity.ResponseResult;
import com.tacit.common.utils.ResCode;
+import com.tacit.common.utils.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/auth")
@@ -39,10 +38,15 @@ public class AuthController {
}
@Operation(summary = "用户退出登录", description = "用户退出登录")
@PostMapping("/logout")
- public ResponseResult logout(HttpServletRequest request) {
- String authorization = request.getHeader("Authorization");
- String token = authorization.substring(CommonConstant.JWT_PREFIX.length());
- userService.logout(token);
+ public ResponseResult logout() {
+ // 从SecurityContext中获取当前用户id
+ Long userId = SecurityUtils.getCurrentUserId();
+ if (userId == null) {
+ return ResponseResult.fail(ResCode.NO_LOGIN.getResultCode(), ResCode.NO_LOGIN.getResultMsg());
+ }
+
+ // 调用服务层处理退出登录
+ userService.logoutByUserId(userId);
return ResponseResult.success(ResCode.LOGOUT.getResultCode(), ResCode.LOGOUT.getResultMsg(), null);
}
}
diff --git a/tacit-admin/src/main/java/com/tacit/admin/service/UserService.java b/tacit-admin/src/main/java/com/tacit/admin/service/UserService.java
index 75d3294..6f666dc 100644
--- a/tacit-admin/src/main/java/com/tacit/admin/service/UserService.java
+++ b/tacit-admin/src/main/java/com/tacit/admin/service/UserService.java
@@ -66,4 +66,10 @@ public interface UserService extends IService {
* 用户退出登录
*/
void logout(String token);
+
+ /**
+ * 根据用户ID退出登录
+ * @param userId 用户ID
+ */
+ void logoutByUserId(Long userId);
}
diff --git a/tacit-admin/src/main/java/com/tacit/admin/service/impl/UserServiceImpl.java b/tacit-admin/src/main/java/com/tacit/admin/service/impl/UserServiceImpl.java
index 376becc..8b1fcc3 100644
--- a/tacit-admin/src/main/java/com/tacit/admin/service/impl/UserServiceImpl.java
+++ b/tacit-admin/src/main/java/com/tacit/admin/service/impl/UserServiceImpl.java
@@ -10,11 +10,11 @@ import com.tacit.admin.entity.dto.RegisterRequest;
import com.tacit.admin.mapper.UserMapper;
import com.tacit.admin.service.RoleService;
import com.tacit.admin.service.UserService;
-import com.tacit.common.utils.JwtUtils;
+import com.tacit.common.constant.CommonConstant;
import com.tacit.common.redis.utils.RedisUtils;
+import com.tacit.common.utils.JwtUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@@ -103,8 +103,12 @@ public class UserServiceImpl extends ServiceImpl implements Us
claims.put("username", user.getUsername());
claims.put("role", user.getRole());
String token = JwtUtils.generateToken(claims);
+
+ // 构建Redis key:tacit:user:token:{userId}
+ String redisKey = CommonConstant.REDIS_KEY_TACIT_USER_TOKEN + user.getId();
// 将生成的 JWT 令牌存储到 Redis 缓存中,设置过期时间为 7 天(7 * 24 * 60 * 60 秒)
- redisUtils.setObject(token, user.getId(),7 * 24 * 60 * 60, TimeUnit.SECONDS);
+ redisUtils.set(redisKey, token ,7 * 24 * 60 * 60, TimeUnit.SECONDS);
+
Role roleMenu = roleService.getRoleByUserId(user.getId());
// 构建登录响应
LoginResponse loginResponse = new LoginResponse();
@@ -119,8 +123,20 @@ public class UserServiceImpl extends ServiceImpl implements Us
*/
@Override
public void logout(String token) {
+ // 从token中解析userId
+ Long userId = JwtUtils.getUserIdFromToken(token);
+ // 构建Redis key:tacit:user:token:{userId}
+ String redisKey = CommonConstant.REDIS_KEY_TACIT_USER_TOKEN + userId;
//清除缓存
- redisUtils.delete(token);
+ redisUtils.delete(redisKey);
+ }
+
+ @Override
+ public void logoutByUserId(Long userId) {
+ // 构建Redis key:tacit:user:token:{userId}
+ String redisKey = CommonConstant.REDIS_KEY_TACIT_USER_TOKEN + userId;
+ //清除缓存
+ redisUtils.delete(redisKey);
}
@Override
diff --git a/tacit-app-api/src/main/java/com/tacit/app/AppApiApplication.java b/tacit-app-api/src/main/java/com/tacit/app/AppApiApplication.java
index d8d9789..d2e590f 100644
--- a/tacit-app-api/src/main/java/com/tacit/app/AppApiApplication.java
+++ b/tacit-app-api/src/main/java/com/tacit/app/AppApiApplication.java
@@ -10,7 +10,6 @@ import com.tacit.common.redis.config.RedisConfig;
@SpringBootApplication
@Import(RedisConfig.class)
@MapperScan("com.tacit.app.mapper")
-@EnableFeignClients(basePackages = "com.tacit.common.feign")
public class AppApiApplication {
public static void main(String[] args) {
SpringApplication.run(AppApiApplication.class, args);
diff --git a/tacit-app-api/src/main/java/com/tacit/app/config/AppSecurityConfig.java b/tacit-app-api/src/main/java/com/tacit/app/config/AppSecurityConfig.java
index ab54def..de1a78b 100644
--- a/tacit-app-api/src/main/java/com/tacit/app/config/AppSecurityConfig.java
+++ b/tacit-app-api/src/main/java/com/tacit/app/config/AppSecurityConfig.java
@@ -62,17 +62,25 @@ public class AppSecurityConfig {
if (authorization != null && authorization.startsWith(CommonConstant.JWT_PREFIX)) {
String token = authorization.substring(CommonConstant.JWT_PREFIX.length());
try {
- // 验证JWT令牌和Redis中的令牌是否存在
- if (JwtUtils.validateToken(token) && redisUtils.hasKey(token)) {
+ // 验证JWT令牌
+ if (JwtUtils.validateToken(token)) {
// 从令牌中获取用户信息
Long userId = JwtUtils.getUserIdFromToken(token);
- String username = JwtUtils.getUsernameFromToken(token);
- String role = JwtUtils.getRoleFromToken(token);
- // 创建认证对象
- User principal = new User(username, "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role.toUpperCase())));
- var authentication = new org.springframework.security.authentication.UsernamePasswordAuthenticationToken(principal, null, principal.getAuthorities());
- SecurityContextHolder.getContext().setAuthentication(authentication);
+ // 构建Redis key:tacit:user:token:{userId}
+ String redisKey = CommonConstant.REDIS_KEY_TACIT_USER_TOKEN + userId;
+
+ // 验证Redis中的令牌是否存在且匹配
+ String redisToken = redisUtils.get(redisKey);
+ if (token.equals(redisToken)) {
+ String username = JwtUtils.getUsernameFromToken(token);
+ String role = JwtUtils.getRoleFromToken(token);
+
+ // 创建认证对象
+ User principal = new User(username, "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role.toUpperCase())));
+ var authentication = new org.springframework.security.authentication.UsernamePasswordAuthenticationToken(principal, null, principal.getAuthorities());
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
}
} catch (Exception e) {
log.error("JWT令牌验证失败: {}", e.getMessage());
diff --git a/tacit-gateway/pom.xml b/tacit-gateway/pom.xml
index 41bd088..99961ea 100644
--- a/tacit-gateway/pom.xml
+++ b/tacit-gateway/pom.xml
@@ -68,12 +68,6 @@
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
-
- com.tacit
- common-redis
- 1.0.0-SNAPSHOT
- compile
-
diff --git a/tacit-gateway/src/main/java/com/tacit/gateway/GatewayApplication.java b/tacit-gateway/src/main/java/com/tacit/gateway/GatewayApplication.java
index 2dc8df7..aa37a66 100644
--- a/tacit-gateway/src/main/java/com/tacit/gateway/GatewayApplication.java
+++ b/tacit-gateway/src/main/java/com/tacit/gateway/GatewayApplication.java
@@ -7,7 +7,6 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
-@Import(RedisConfig.class)
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
diff --git a/tacit-gateway/src/main/java/com/tacit/gateway/filter/JwtAuthenticationFilter.java b/tacit-gateway/src/main/java/com/tacit/gateway/filter/JwtAuthenticationFilter.java
index 4c004e0..4191eea 100644
--- a/tacit-gateway/src/main/java/com/tacit/gateway/filter/JwtAuthenticationFilter.java
+++ b/tacit-gateway/src/main/java/com/tacit/gateway/filter/JwtAuthenticationFilter.java
@@ -30,7 +30,6 @@ public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory WHITE_LIST = List.of(
"/auth/login",
"/auth/register",
- "/auth/login",
"/auth/register",
"/swagger-ui",
"/v3/api-docs"
@@ -53,33 +52,40 @@ public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory