多OAuth2资源服务器如何实现?多资源服务端配置方案咨询
Great question! When you need to integrate with more than one OAuth2 resource server (like adding a second one alongside Facebook), the default single-entry security.oauth2.resource setup in application.yml won't work. Here are two practical, production-ready approaches to solve this:
1. Custom Configuration Properties + Java Config (Flexible for Older Spring Versions)
This method lets you define multiple resource server configurations in your YAML and map them to Spring Security beans, giving you full control over each integration.
Step 1: Update application.yml with Named Resource Server Configs
Add dedicated sections for each resource server (we'll use Facebook and GitHub as examples):
security: oauth2: client: # Keep your existing Facebook client configuration here clientId: 233668646673605 clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d accessTokenUri: https://graph.facebook.com/oauth/access_token userAuthorizationUri: https://www.facebook.com/dialog/oauth tokenName: oauth_token authenticationScheme: query clientAuthenticationScheme: form # Add custom multi-resource server properties resources: facebook: userInfoUri: https://graph.facebook.com/me github: userInfoUri: https://api.github.com/user tokenInfoUri: https://api.github.com/oauth2/tokeninfo
Step 2: Bind Custom Properties to Java Classes
Create configuration classes to map your YAML properties into usable objects:
@ConfigurationProperties(prefix = "security.oauth2.resources") public class MultiResourceServerProperties { private ResourceServerProps facebook; private ResourceServerProps github; // Getters and setters } // Reusable class for resource server details public class ResourceServerProps { private String userInfoUri; private String tokenInfoUri; // Getters and setters }
Step 3: Configure Spring Security for Multiple Resources
Build a security config that routes requests to the correct resource server validation logic:
@Configuration @EnableOAuth2Client @EnableResourceServer @EnableConfigurationProperties(MultiResourceServerProperties.class) public class MultiResourceServerConfig extends ResourceServerConfigurerAdapter { private final MultiResourceServerProperties resourceProps; private final OAuth2ClientContext oauth2ClientContext; public MultiResourceServerConfig(MultiResourceServerProperties resourceProps, OAuth2ClientContext oauth2ClientContext) { this.resourceProps = resourceProps; this.oauth2ClientContext = oauth2ClientContext; } @Override public void configure(HttpSecurity http) throws Exception { // Route /facebook/** requests to Facebook's resource server validation http.antMatcher("/facebook/**") .authorizeRequests().anyRequest().authenticated() .and() .oauth2ResourceServer() .userInfoTokenServices(facebookTokenServices()); // Route /github/** requests to GitHub's resource server validation http.antMatcher("/github/**") .authorizeRequests().anyRequest().authenticated() .and() .oauth2ResourceServer() .userInfoTokenServices(githubTokenServices()); } // Facebook token validation setup private UserInfoTokenServices facebookTokenServices() { UserInfoTokenServices services = new UserInfoTokenServices( resourceProps.getFacebook().getUserInfoUri(), "233668646673605" // Facebook client ID ); services.setRestTemplate(new OAuth2RestTemplate(facebookClientDetails(), oauth2ClientContext)); return services; } private ClientDetails facebookClientDetails() { return ClientDetailsBuilder.create() .clientId("233668646673605") .clientSecret("33b17e044ee6a4fa383f46ec6e28ea1d") .build(); } // GitHub token validation setup private UserInfoTokenServices githubTokenServices() { UserInfoTokenServices services = new UserInfoTokenServices( resourceProps.getGithub().getUserInfoUri(), "your-github-client-id" // Replace with your GitHub client ID ); services.setRestTemplate(new OAuth2RestTemplate(githubClientDetails(), oauth2ClientContext)); return services; } private ClientDetails githubClientDetails() { return ClientDetailsBuilder.create() .clientId("your-github-client-id") .clientSecret("your-github-client-secret") // Replace with your GitHub client secret .build(); } }
2. Native Multi-Resource Server Support (Spring Security 5.3+)
If you're using Spring Security 5.3 or later, the framework has built-in support for multiple resource servers, making the setup cleaner.
Step 1: Update application.yml
Define separate properties for each resource server:
spring: security: oauth2: resourceserver: facebook: opaquetoken: user-info-uri: https://graph.facebook.com/me client-id: 233668646673605 client-secret: 33b17e044ee6a4fa383f46ec6e28ea1d github: opaquetoken: user-info-uri: https://api.github.com/user client-id: your-github-client-id client-secret: your-github-client-secret
Step 2: Build the Security Filter Chain
Use Spring Security's modern filter chain API to route requests to the correct token introspector:
@Configuration public class ModernMultiResourceServerConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/facebook/**", "/github/**").authenticated() .anyRequest().permitAll() ) // Add Facebook resource server handling .oauth2ResourceServer(oauth2 -> oauth2 .opaqueToken(opaque -> opaque .filter(new ResourceServerFilter("/facebook/**", facebookIntrospector())) ) ) // Add GitHub resource server handling .oauth2ResourceServer(oauth2 -> oauth2 .opaqueToken(opaque -> opaque .filter(new ResourceServerFilter("/github/**", githubIntrospector())) ) ); return http.build(); } @Bean @ConfigurationProperties("spring.security.oauth2.resourceserver.facebook.opaquetoken") public OpaqueTokenIntrospector facebookIntrospector() { return new NimbusOpaqueTokenIntrospector( "https://graph.facebook.com/oauth/access_token", "233668646673605", "33b17e044ee6a4fa383f46ec6e28ea1d" ); } @Bean @ConfigurationProperties("spring.security.oauth2.resourceserver.github.opaquetoken") public OpaqueTokenIntrospector githubIntrospector() { return new NimbusOpaqueTokenIntrospector( "https://api.github.com/oauth2/tokeninfo", "your-github-client-id", "your-github-client-secret" ); } // Custom filter to route requests to the correct introspector private static class ResourceServerFilter extends OncePerRequestFilter { private final String pathPrefix; private final OpaqueTokenIntrospector introspector; public ResourceServerFilter(String pathPrefix, OpaqueTokenIntrospector introspector) { this.pathPrefix = pathPrefix; this.introspector = introspector; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { if (request.getRequestURI().startsWith(pathPrefix)) { request.setAttribute(OAuth2ResourceServerAuthenticationFilter.class.getName() + ".OPAQUE_TOKEN_INTROSPECTOR", introspector); } chain.doFilter(request, response); } } }
Key Takeaways
- Path Routing: Use
antMatcher(orrequestMatchersin newer versions) to ensure each endpoint uses the correct resource server validation logic. - Token Types: For opaque tokens (like Facebook's), use user info or token introspection endpoints. For JWT tokens, replace the introspector with a JWT decoder using a JWKS URI.
- Isolation: Each resource server gets its own client credentials and validation setup, so changes to one don't break the other.
内容的提问来源于stack exchange,提问作者user5685187

