Spring Boot OAuth2客户端适配自定义认证服务器无Filter实现咨询
Spring Boot OAuth2客户端适配自定义认证服务器(非标准参数)
我来帮你梳理下这个问题,其实Spring Security OAuth2 Client的扩展性很强,完全不需要用Filter做请求重定向,咱们可以通过官方提供的扩展点来完美适配你的自定义认证服务器规则。先明确下你的核心需求:
- 用
api_key替代标准client_id,api_secret替代client_secret - 回调返回
request_token而非code,且无state参数
下面是完整的正确实现方案,全程不需要Filter重定向:
核心思路:利用Spring OAuth2的扩展点适配非标准规则
Spring OAuth2 Client提供了多个可扩展接口,咱们只需针对三个核心环节做自定义处理:
- 认证请求阶段:替换
client_id为api_key,移除不必要的state参数 - 回调响应阶段:将
request_token直接映射为标准code参数 - Token获取阶段:替换Token请求中的
client_id/client_secret为api_key/api_secret
1. 基础客户端配置(application.yml)
先在配置文件里定义你的客户端信息,把client-id和client-secret对应到你的api_key和api_secret,同时配置认证和Token端点:
spring: security: oauth2: client: registration: kite: client-id: YOUR_ACTUAL_API_KEY client-secret: YOUR_ACTUAL_API_SECRET authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/oauth/callback/kite" scope: [read, write] # 根据你的认证服务器需求调整 provider: kite: authorization-uri: https://your-oauth-server/authorize # 你的认证服务器授权地址 token-uri: https://your-oauth-server/token # 你的认证服务器Token地址
2. 自定义认证请求解析器(替换ClientID为API Key)
这个组件负责构建发送给认证服务器的授权请求,咱们在这里替换参数名并移除state:
@Component public class KiteAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver { private final DefaultOAuth2AuthorizationRequestResolver delegateResolver; private final ClientRegistration kiteClient; public KiteAuthorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository, @Value("/oauth2/authorization") String authorizationBaseUri) { this.delegateResolver = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, authorizationBaseUri); this.kiteClient = clientRegistrationRepository.findByRegistrationId("kite"); } @Override public OAuth2AuthorizationRequest resolve(HttpServletRequest request) { return customizeRequest(delegateResolver.resolve(request)); } @Override public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) { return customizeRequest(delegateResolver.resolve(request, clientRegistrationId)); } private OAuth2AuthorizationRequest customizeRequest(OAuth2AuthorizationRequest request) { if (request == null || !"kite".equals(request.getClientRegistration().getRegistrationId())) { return request; } // 构建新的请求参数:替换client_id为api_key,移除默认client_id Map<String, Object> additionalParams = new HashMap<>(request.getAdditionalParameters()); additionalParams.put("api_key", kiteClient.getClientId()); additionalParams.remove("client_id"); // 移除state参数(你的服务器不需要) return OAuth2AuthorizationRequest.from(request) .state(null) .additionalParameters(additionalParams) .build(); } }
3. 自定义回调响应解析器(映射request_token为code)
这个组件负责处理认证服务器的回调请求,直接把request_token提取出来当作标准code使用,完全不需要重定向:
@Component public class KiteAuthorizationResponseResolver implements OAuth2AuthorizationResponseResolver { private final DefaultOAuth2AuthorizationResponseResolver delegateResolver; public KiteAuthorizationResponseResolver() { this.delegateResolver = new DefaultOAuth2AuthorizationResponseResolver(); } @Override public OAuth2AuthorizationResponse resolve(HttpServletRequest request) { // 从回调请求中获取request_token参数 String requestToken = request.getParameter("request_token"); if (requestToken != null && !requestToken.isEmpty()) { // 构建标准的AuthorizationResponse,将request_token作为code返回 return OAuth2AuthorizationResponse.success(requestToken) .redirectUri(request.getRequestURL().toString()) .build(); } // 其他情况用默认逻辑处理 return delegateResolver.resolve(request); } }
4. 自定义Token请求转换器(替换Token请求参数)
在向认证服务器请求Token时,咱们需要把client_id/client_secret替换为api_key/api_secret:
public class KiteTokenRequestConverter extends AbstractOAuth2TokenRequestConverter { @Override protected void populateTokenRequestBody(OAuth2TokenRequest tokenRequest, MultiValueMap<String, String> body) { super.populateTokenRequestBody(tokenRequest, body); ClientRegistration clientRegistration = tokenRequest.getClientRegistration(); if ("kite".equals(clientRegistration.getRegistrationId())) { // 替换参数名 body.add("api_key", clientRegistration.getClientId()); body.add("api_secret", clientRegistration.getClientSecret()); // 移除默认的client_id和client_secret参数 body.remove("client_id"); body.remove("client_secret"); } } }
5. 配置SecurityFilterChain,注册所有自定义组件
最后在Security配置里把这些自定义组件注册到OAuth2登录流程中:
@Configuration @EnableWebSecurity public class SecurityConfig { private final KiteAuthorizationRequestResolver authorizationRequestResolver; private final KiteAuthorizationResponseResolver authorizationResponseResolver; private final ClientRegistrationRepository clientRegistrationRepository; // 构造注入组件 public SecurityConfig(KiteAuthorizationRequestResolver authorizationRequestResolver, KiteAuthorizationResponseResolver authorizationResponseResolver, ClientRegistrationRepository clientRegistrationRepository) { this.authorizationRequestResolver = authorizationRequestResolver; this.authorizationResponseResolver = authorizationResponseResolver; this.clientRegistrationRepository = clientRegistrationRepository; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .oauth2Login(oauth2 -> oauth2 // 注册自定义认证请求解析器 .authorizationEndpoint(endpoint -> endpoint .authorizationRequestResolver(authorizationRequestResolver) ) // 注册自定义回调响应解析器 .redirectionEndpoint(endpoint -> endpoint .authorizationResponseResolver(authorizationResponseResolver) ) // 注册自定义Token请求转换器 .tokenEndpoint(endpoint -> endpoint .accessTokenResponseClient(customAccessTokenResponseClient()) ) ); return http.build(); } private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> customAccessTokenResponseClient() { DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient(); tokenResponseClient.setRequestEntityConverter(new KiteTokenRequestConverter()); return tokenResponseClient; } }
关键说明:完全不需要Filter重定向
通过上面的实现,咱们已经完全绕开了Filter重定向的需求:
- 回调中的
request_token直接被KiteAuthorizationResponseResolver解析为标准code,不需要再做URL重定向 - 所有参数替换都基于Spring Security官方扩展接口,符合框架设计规范,避免了自定义Filter可能带来的请求顺序、URL匹配等问题
- 代码结构更清晰,后续维护也更方便
内容的提问来源于stack exchange,提问作者Pavan Kumar
相关产品推荐
相关产品推荐

