Spring Boot 3.1.x开发环境下OAuth2资源服务器模拟认证方案
Spring Boot 3.1.x 开发环境模拟OAuth2资源服务器用户方案
针对你在开发环境下需要模拟OIDC代理认证用户的需求,这里给你一套可通过application.properties配置角色、自定义声明的实现方案,无需修改业务代码,就能让所有Principal消费者拿到符合要求的已认证对象:
1. 配置开发环境的模拟用户信息
在application-dev.properties中添加自定义配置,用来定义模拟用户的基础信息、角色和自定义声明:
# 模拟用户核心信息 dev.auth.username=dev-user dev.auth.email=dev@example.com # 多角色用逗号分隔 dev.auth.roles=ADMIN,USER # 自定义声明(支持键值对形式) dev.auth.claims.tenant-id=123 dev.auth.claims.department=dev-team
2. 编写开发环境专属的认证过滤器
创建一个仅在dev profile下生效的过滤器,生成模拟的JWT认证对象并注入到SecurityContext中,完全贴合OAuth2资源服务器的认证模型:
import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.util.*; import java.util.stream.Collectors; @Component @Profile("dev") // 仅在开发环境启用 public class DevMockAuthFilter extends OncePerRequestFilter { @Value("${dev.auth.username}") private String username; @Value("${dev.auth.email}") private String email; @Value("${dev.auth.roles}") private String roles; @Value("#{${dev.auth.claims}}") private Map<String, Object> customClaims; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, java.io.IOException { // 构建JWT声明集合 Map<String, Object> claims = new HashMap<>(); claims.put("sub", username); claims.put("email", email); claims.put("roles", Arrays.asList(roles.split(","))); claims.putAll(customClaims); // 生成模拟JWT对象 Jwt jwt = Jwt.withTokenValue("mock-jwt-token") .header("alg", "none") .claims(claims) .build(); // 转换为Spring Security的权限对象 Collection<? extends GrantedAuthority> authorities = Arrays.stream(roles.split(",")) .map(role -> new SimpleGrantedAuthority("ROLE_" + role)) .collect(Collectors.toList()); // 注入认证信息到上下文 Authentication authentication = new JwtAuthenticationToken(jwt, authorities); org.springframework.security.core.context.SecurityContextHolder.getContext().setAuthentication(authentication); filterChain.doFilter(request, response); } }
3. 配置Spring Security环境隔离
通过@Profile注解区分开发和生产环境的Security配置,开发环境使用模拟过滤器,生产环境保持原有的OAuth2资源服务器配置:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity public class SecurityConfig { private final DevMockAuthFilter devMockAuthFilter; public SecurityConfig(DevMockAuthFilter devMockAuthFilter) { this.devMockAuthFilter = devMockAuthFilter; } // 开发环境配置:启用模拟认证 @Bean @Profile("dev") public SecurityFilterChain devSecurityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) // 把模拟过滤器放到默认认证过滤器之前 .addFilterBefore(devMockAuthFilter, UsernamePasswordAuthenticationFilter.class) // 所有请求需要认证(模拟过滤器已经处理认证逻辑) .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()); return http.build(); } // 生产环境配置:正常使用OAuth2资源服务器 @Bean @Profile("!dev") public SecurityFilterChain prodSecurityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt // 这里配置你生产环境的JWT转换器逻辑 )); return http.build(); } }
4. 验证模拟效果
启动应用时激活dev profile(可以通过VM参数-Dspring.profiles.active=dev,或者在application.properties中设置spring.profiles.active=dev),然后在业务代码中正常获取认证信息即可,比如Controller:
import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; @RestController public class TestController { @GetMapping("/me") public Map<String, Object> getCurrentUser(@AuthenticationPrincipal Jwt jwt) { return Map.of( "username", jwt.getSubject(), "email", jwt.getClaim("email"), "roles", jwt.getClaim("roles"), "tenantId", jwt.getClaim("tenant-id"), "authorities", jwt.getAuthorities() ); } }
访问/me接口就能看到配置的模拟用户信息,所有依赖Principal的服务都会自动使用这个模拟的认证对象,和真实OIDC代理认证的效果完全一致。
内容的提问来源于stack exchange,提问作者KhaosTheory
相关产品推荐
相关产品推荐

