Spring Boot OAuth2客户端能否在初始请求指定登录后重定向地址?
动态设置OAuth2社交登录的redirect_uri解决方案
针对跨平台Web/App需要不同登录回调地址的场景,你可以通过自定义Spring Security的OAuth2AuthorizationRequestResolver来实现动态指定redirect_uri的需求,具体步骤如下:
1. 自定义授权请求解析器
重写默认的授权请求解析逻辑,从请求参数中提取自定义的redirect_uri,并替换预配置的回调地址,同时加入安全校验防止非法地址:
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import jakarta.servlet.http.HttpServletRequest; import java.util.Map; public class DynamicRedirectUriAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver { private final OAuth2AuthorizationRequestResolver delegate; public DynamicRedirectUriAuthorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository, String authorizationRequestBaseUri) { this.delegate = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, authorizationRequestBaseUri); } @Override public OAuth2AuthorizationRequest resolve(HttpServletRequest request) { OAuth2AuthorizationRequest authorizationRequest = this.delegate.resolve(request); return customizeAuthorizationRequest(authorizationRequest, request); } @Override public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) { OAuth2AuthorizationRequest authorizationRequest = this.delegate.resolve(request, clientRegistrationId); return customizeAuthorizationRequest(authorizationRequest, request); } private OAuth2AuthorizationRequest customizeAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest, HttpServletRequest request) { if (authorizationRequest == null) { return null; } // 从请求参数获取自定义redirect_uri String dynamicRedirectUri = request.getParameter("redirect_uri"); if (dynamicRedirectUri != null && !dynamicRedirectUri.isEmpty()) { // 校验redirect_uri合法性,避免开放重定向攻击 if (isValidRedirectUri(dynamicRedirectUri)) { return OAuth2AuthorizationRequest.from(authorizationRequest) .redirectUri(dynamicRedirectUri) .additionalParameters(authorizationRequest.getAdditionalParameters()) .build(); } } return authorizationRequest; } // 自定义合法地址校验逻辑,可根据实际需求扩展 private boolean isValidRedirectUri(String redirectUri) { return redirectUri.startsWith("foo://") || redirectUri.startsWith("bar://"); } }
2. 配置Spring Security
在安全配置类中替换默认的授权请求解析器,并自定义登录成功处理器完成最终跳转:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http, ClientRegistrationRepository clientRegistrationRepository) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/auth/**").permitAll() .anyRequest().authenticated() ) .oauth2Login(oauth2 -> oauth2 .authorizationEndpoint(authEndpoint -> authEndpoint // 注入自定义的授权请求解析器 .authorizationRequestResolver( new DynamicRedirectUriAuthorizationRequestResolver(clientRegistrationRepository, "/auth/oauth2/authorize") ) ) // 自定义登录成功后的跳转逻辑 .successHandler((request, response, authentication) -> { String redirectUri = request.getParameter("redirect_uri"); if (redirectUri != null && isValidRedirectUri(redirectUri)) { response.sendRedirect(redirectUri); } else { // 兜底的默认跳转地址 response.sendRedirect("/"); } }) ); return http.build(); } private boolean isValidRedirectUri(String redirectUri) { return redirectUri.startsWith("foo://") || redirectUri.startsWith("bar://"); } }
3. 关键注意事项
- 安全校验不可少:必须对传入的redirect_uri做合法性校验,只允许预定义的可信地址,防止恶意的开放重定向攻击。
- 服务商配置同步:需要在Google等OAuth2服务商的控制台中,将动态使用的redirect_uri(如
foo://、bar://对应的回调地址)添加到允许列表中,否则会被服务商拒绝授权请求。 - 参数持久化(可选):如果登录流程中请求参数可能丢失,可以将redirect_uri存入session,在successHandler中取出使用。
内容的提问来源于stack exchange,提问作者BottleMoon
相关产品推荐
相关产品推荐

