修改redis的缓存
This commit is contained in:
parent
70fe35510b
commit
a174cb255f
|
|
@ -49,6 +49,13 @@
|
|||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Security -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing -->
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -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:";
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@
|
|||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tacit</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud Alibaba Nacos Discovery -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -0,0 +1 @@
|
|||
com.tacit.common.feign.config.FeignGlobalConfig
|
||||
|
|
@ -20,6 +20,11 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<!-- Spring Boot Auto Configure -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Jedis -->
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -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<String, Object> redisTemplate(RedisConnectionFactory factory) {
|
||||
public RedisTemplate<String, Object> stringObjectRedisTemplate(RedisConnectionFactory factory) {
|
||||
RedisTemplate<String, Object> 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, Object> redisTemplate;
|
||||
|
||||
@Autowired
|
||||
|
|
@ -345,7 +346,7 @@ public class RedisUtils {
|
|||
|
||||
/**
|
||||
* 删除键
|
||||
* @param key 键(可以多个)
|
||||
* @param keys 键(可以多个)
|
||||
*/
|
||||
public void delete(String... keys) {
|
||||
if (keys != null && keys.length > 0) {
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.tacit.common.redis.config.RedisConfig
|
||||
|
|
@ -0,0 +1 @@
|
|||
com.tacit.common.redis.config.RedisConfig
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.tacit.common.xxljob.XxlJobAutoConfiguration
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<String, Object> 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<String, Object> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Void> logout(HttpServletRequest request) {
|
||||
String authorization = request.getHeader("Authorization");
|
||||
String token = authorization.substring(CommonConstant.JWT_PREFIX.length());
|
||||
userService.logout(token);
|
||||
public ResponseResult<Void> logout() {
|
||||
// 从SecurityContext中获取当前用户id
|
||||
Long userId = SecurityUtils.getCurrentUserId();
|
||||
if (userId == null) {
|
||||
return ResponseResult.<Void>fail(ResCode.NO_LOGIN.getResultCode(), ResCode.NO_LOGIN.getResultMsg());
|
||||
}
|
||||
|
||||
// 调用服务层处理退出登录
|
||||
userService.logoutByUserId(userId);
|
||||
return ResponseResult.<Void>success(ResCode.LOGOUT.getResultCode(), ResCode.LOGOUT.getResultMsg(), null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,4 +66,10 @@ public interface UserService extends IService<User> {
|
|||
* 用户退出登录
|
||||
*/
|
||||
void logout(String token);
|
||||
|
||||
/**
|
||||
* 根据用户ID退出登录
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
void logoutByUserId(Long userId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UserMapper, User> 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<UserMapper, User> 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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -68,12 +68,6 @@
|
|||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.tacit</groupId>
|
||||
<artifactId>common-redis</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory<JwtAut
|
|||
private static final List<String> 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<JwtAut
|
|||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
// 获取Authorization头
|
||||
// 获取 Authorization头
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
String authorization = headers.getFirst(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
// 检查Authorization头是否存在
|
||||
// 检查 Authorization头是否存在
|
||||
if (authorization == null || authorization.isEmpty()) {
|
||||
return unauthorizedResponse(exchange, "缺少认证令牌");
|
||||
}
|
||||
|
||||
// 检查Authorization头格式
|
||||
// 检查 Authorization头格式
|
||||
if (!authorization.startsWith(CommonConstant.JWT_PREFIX)) {
|
||||
return unauthorizedResponse(exchange, "认证令牌格式错误");
|
||||
}
|
||||
|
||||
// 提取JWT令牌
|
||||
// 提取 JWT令牌
|
||||
String token = authorization.substring(CommonConstant.JWT_PREFIX.length());
|
||||
|
||||
// 验证JWT令牌
|
||||
// 验证 JWT令牌
|
||||
try {
|
||||
boolean isTokenValid = redisUtils.hasKey(token);
|
||||
if (!isTokenValid) {
|
||||
JwtUtils.validateToken(token);
|
||||
|
||||
// 从令牌中获取用户信息
|
||||
Long userId = JwtUtils.getUserIdFromToken(token);
|
||||
|
||||
// 构建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)) {
|
||||
return unauthorizedResponse(exchange, "Token已被注销");
|
||||
}
|
||||
JwtUtils.validateToken(token);
|
||||
|
||||
// 从令牌中获取用户信息并添加到请求头
|
||||
Long userId = JwtUtils.getUserIdFromToken(token);
|
||||
String username = JwtUtils.getUsernameFromToken(token);
|
||||
String role = JwtUtils.getRoleFromToken(token);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue