You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 16:35:36