网关问题
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package org.xyzh.common.auth.config;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.xyzh.common.auth.contants.AuthContants;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @description Gateway 认证模式配置 - 信任 Gateway 传递的用户信息
|
||||
* @author yslg
|
||||
* @since 2025-12-02
|
||||
*
|
||||
* 当启用 gateway-mode 时,微服务不再独立验证 JWT,而是信任 Gateway 传递的用户信息
|
||||
* 配置项:auth.gateway-mode=true
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(name = "auth.gateway-mode", havingValue = "true")
|
||||
public class GatewayAuthConfig {
|
||||
private static final Logger log = LoggerFactory.getLogger(GatewayAuthConfig.class);
|
||||
|
||||
/**
|
||||
* Gateway 信任过滤器 - 从请求头获取用户信息
|
||||
* 替代 JwtAuthenticationFilter
|
||||
*/
|
||||
@Bean
|
||||
public GatewayTrustFilter gatewayTrustFilter() {
|
||||
log.info("启用 Gateway 认证模式,微服务将信任 Gateway 传递的用户信息");
|
||||
return new GatewayTrustFilter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gateway 信任过滤器实现
|
||||
*/
|
||||
public static class GatewayTrustFilter extends OncePerRequestFilter {
|
||||
private static final Logger log = LoggerFactory.getLogger(GatewayTrustFilter.class);
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(@NonNull HttpServletRequest request,
|
||||
@NonNull HttpServletResponse response,
|
||||
@NonNull FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
// 从 Gateway 传递的请求头获取用户信息
|
||||
String userId = request.getHeader(AuthContants.USER_ID_ATTRIBUTE);
|
||||
String username = request.getHeader(AuthContants.USERNAME_ATTRIBUTE);
|
||||
|
||||
if (StringUtils.hasText(userId)) {
|
||||
// 构造简化的 Principal(使用 userId 作为身份标识)
|
||||
// 注意:完整的 LoginDomain 应该从 Redis 加载,这里只是基本身份验证
|
||||
|
||||
// 设置到 Spring Security 上下文
|
||||
UsernamePasswordAuthenticationToken authentication =
|
||||
new UsernamePasswordAuthenticationToken(userId, null, Collections.emptyList());
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
// 同时将用户信息设置到 request attributes 中,供业务代码使用
|
||||
request.setAttribute(AuthContants.USER_ID_ATTRIBUTE, userId);
|
||||
if (StringUtils.hasText(username)) {
|
||||
request.setAttribute(AuthContants.USERNAME_ATTRIBUTE, username);
|
||||
}
|
||||
|
||||
log.debug("从 Gateway 获取用户信息: userId={}, username={}", userId, username);
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.xyzh.common.auth.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
@@ -15,17 +17,29 @@ import org.xyzh.redis.service.RedisService;
|
||||
@EnableMethodSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
/**
|
||||
* JWT 认证过滤器 - 仅在非 Gateway 模式下启用
|
||||
* 当 auth.gateway-mode=false 或未配置时使用
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "auth.gateway-mode", havingValue = "false", matchIfMissing = true)
|
||||
public JwtAuthenticationFilter jwtAuthenticationFilter(TokenParser tokenParser,
|
||||
AuthProperties authProperties,
|
||||
RedisService redisService) {
|
||||
return new JwtAuthenticationFilter(tokenParser, authProperties, redisService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Security 过滤器链配置
|
||||
* 根据是否启用 Gateway 模式决定是否添加 JWT 过滤器
|
||||
*/
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http,
|
||||
AuthProperties authProperties,
|
||||
JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception {
|
||||
public SecurityFilterChain securityFilterChain(
|
||||
HttpSecurity http,
|
||||
AuthProperties authProperties,
|
||||
@Autowired(required = false) JwtAuthenticationFilter jwtAuthenticationFilter,
|
||||
@Autowired(required = false) GatewayAuthConfig.GatewayTrustFilter gatewayTrustFilter) throws Exception {
|
||||
|
||||
http
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.formLogin(form -> form.disable())
|
||||
@@ -45,8 +59,16 @@ public class SecurityConfig {
|
||||
authz
|
||||
.requestMatchers("/error", "/favicon.ico").permitAll()
|
||||
.anyRequest().authenticated();
|
||||
})
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
});
|
||||
|
||||
// 根据模式添加对应的过滤器
|
||||
if (jwtAuthenticationFilter != null) {
|
||||
// 非 Gateway 模式:使用 JWT 过滤器
|
||||
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
} else if (gatewayTrustFilter != null) {
|
||||
// Gateway 模式:使用信任过滤器
|
||||
http.addFilterBefore(gatewayTrustFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user