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

如何为Spring Security社交登录授权URI添加自定义查询参数

给Spring Security OAuth2授权URI追加自定义查询参数

问题背景

当前使用Spring Security 5.2.12.RELEASE实现谷歌、脸书等社交平台的OAuth2登录,登录流程为调用端点https://example.com/oauth2/authorize/{registrationId},会话信息存入Cookie后重定向到服务商授权URI。

现有核心配置如下:

SecurityConfig.java

package com.example.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.example.security.*;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        securedEnabled = true,
        jsr250Enabled = true,
        prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomOAuth2UserService customOAuth2UserService;

    @Autowired
    private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;

    @Autowired
    private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;

    @Autowired
    private HttpCookieOAuth2AuthorizationRequestRepository httpCookieOAuth2AuthorizationRequestRepository;

    @Bean
    public TokenAuthenticationFilter tokenAuthenticationFilter() {
        return new TokenAuthenticationFilter();
    }

    /*
      By default, Spring OAuth2 uses HttpSessionOAuth2AuthorizationRequestRepository to save
      the authorization request. But, since our service is stateless, we can't save it in
      the session. We'll save the request in a Base64 encoded cookie instead.
    */
    @Bean
    public HttpCookieOAuth2AuthorizationRequestRepository cookieAuthorizationRequestRepository() {
        return new HttpCookieOAuth2AuthorizationRequestRepository();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors()
                    .and()
                .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                .csrf()
                    .disable()
                .formLogin()
                    .disable()
                .httpBasic()
                    .disable()
                .exceptionHandling()
                    .authenticationEntryPoint(new RestAuthenticationEntryPoint())
                    .and()
                .authorizeRequests()
                    .antMatchers("/oauth2/**")
                        .permitAll()
                    .anyRequest()
                        .authenticated()
                    .and()
                .oauth2Login()
                    .authorizationEndpoint()
                        .baseUri("/oauth2/authorize")
                        .authorizationRequestRepository(cookieAuthorizationRequestRepository())
                        .and()
                    .redirectionEndpoint()
                        .baseUri("/oauth2/callback/*")
                        .and()
                    .userInfoEndpoint()
                        .userService(customOAuth2UserService)
                        .and()
                    .successHandler(oAuth2AuthenticationSuccessHandler)
                    .failureHandler(oAuth2AuthenticationFailureHandler)
                    ;

        // Add our custom Token based authentication filter
        http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    public HttpCookieOAuth2AuthorizationRequestRepository getHttpCookieOAuth2AuthorizationRequestRepository() {
        return httpCookieOAuth2AuthorizationRequestRepository;
    }

    public void setHttpCookieOAuth2AuthorizationRequestRepository(
            HttpCookieOAuth2AuthorizationRequestRepository httpCookieOAuth2AuthorizationRequestRepository) {
        this.httpCookieOAuth2AuthorizationRequestRepository = httpCookieOAuth2AuthorizationRequestRepository;
    }
}

application.properties(谷歌OAuth2配置)

#Social Providers OAuth2 settings
spring.security.oauth2.client.registration.google.clientId=abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com
spring.security.oauth2.client.registration.google.clientSecret=secret
spring.security.oauth2.client.registration.google.redirectUri=https://example.com/oauth2/callback/{registrationId}
spring.security.oauth2.client.registration.google.scope=email,profile

当前生成的谷歌授权URI示例:

https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount
    ?response_type=code
    &client_id=abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com
    &scope=email%20profile
    &state=zyxwvutsrqponmlkjihgfedcba
    &redirect_uri=https%3A%2F%2Fexample.com%2Foauth2%2Fcallback%2Fgoogle
    &service=lso
    &o2v=2
    &flowName=GeneralOAuthFlow

需要给该URI追加查询参数&prompt=select_account,但直接在application.properties中添加spring.security.oauth2.client.registration.google.prompt=select_account无效,官方文档未提供该配置项。

解决方案

通过自定义OAuth2AuthorizationRequestResolver来修改授权请求的额外参数,具体步骤如下:

1. 实现自定义的OAuth2AuthorizationRequestResolver

import org.springframework.security.oauth2.client.registration.ClientRegistration;
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 javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

public class CustomOAuth2AuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {

    private final OAuth2AuthorizationRequestResolver delegate;

    public CustomOAuth2AuthorizationRequestResolver(OAuth2AuthorizationRequestResolver delegate) {
        this.delegate = delegate;
    }

    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
        OAuth2AuthorizationRequest authorizationRequest = this.delegate.resolve(request);
        return customizeAuthorizationRequest(authorizationRequest);
    }

    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
        OAuth2AuthorizationRequest authorizationRequest = this.delegate.resolve(request, clientRegistrationId);
        return customizeAuthorizationRequest(authorizationRequest);
    }

    private OAuth2AuthorizationRequest customizeAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest) {
        if (authorizationRequest == null) {
            return null;
        }

        // 仅针对谷歌客户端追加prompt参数,其他平台可按需扩展
        ClientRegistration clientRegistration = authorizationRequest.getClientRegistration();
        if ("google".equals(clientRegistration.getRegistrationId())) {
            Map<String, Object> additionalParams = new HashMap<>(authorizationRequest.getAdditionalParameters());
            additionalParams.put("prompt", "select_account");
            
            return OAuth2AuthorizationRequest.from(authorizationRequest)
                    .additionalParameters(additionalParams)
                    .build();
        }

        return authorizationRequest;
    }
}

2. 在SecurityConfig中配置自定义Resolver

首先注入ClientRegistrationRepository,然后修改configure(HttpSecurity http)方法中的oauth2Login配置:

// 在SecurityConfig类中添加注入
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 创建默认授权请求解析器,并用自定义解析器包装
    OAuth2AuthorizationRequestResolver defaultResolver = new DefaultOAuth2AuthorizationRequestResolver(
            clientRegistrationRepository, "/oauth2/authorize");
    OAuth2AuthorizationRequestResolver customResolver = new CustomOAuth2AuthorizationRequestResolver(defaultResolver);

    http
            .cors()
                .and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .csrf()
                .disable()
            .formLogin()
                .disable()
            .httpBasic()
                .disable()
            .exceptionHandling()
                .authenticationEntryPoint(new RestAuthenticationEntryPoint())
                .and()
            .authorizeRequests()
                .antMatchers("/oauth2/**")
                    .permitAll()
                .anyRequest()
                    .authenticated()
                .and()
            .oauth2Login()
                .authorizationEndpoint()
                    .baseUri("/oauth2/authorize")
                    .authorizationRequestRepository(cookieAuthorizationRequestRepository())
                    // 配置自定义授权请求解析器
                    .authorizationRequestResolver(customResolver)
                    .and()
                .redirectionEndpoint()
                    .baseUri("/oauth2/callback/*")
                    .and()
                .userInfoEndpoint()
                    .userService(customOAuth2UserService)
                    .and()
                .successHandler(oAuth2AuthenticationSuccessHandler)
                .failureHandler(oAuth2AuthenticationFailureHandler);

    http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

原理说明

Spring Security的DefaultOAuth2AuthorizationRequestResolver负责构建OAuth2授权请求的URI,我们通过包装该解析器,在授权请求构建完成后追加自定义参数,最终生成的授权URI会包含prompt=select_account参数。

内容的提问来源于stack exchange,提问作者nick_j_white

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 01:15:07