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

Spring Security OAuth2登录成功处理器中OAuth2AuthorizationRequest为空问题排查

Spring Security Google OAuth2登录后AuthorizationRequest为空的问题解决

问题原因

Spring Security在OAuth2登录的默认流程中,OAuth2LoginAuthenticationProvider完成认证逻辑后,会调用你配置的HttpSessionOAuth2AuthorizationRequestRepository的removeAuthorizationRequest方法,提前清除会话中的授权请求对象。等你的自定义AuthenticationSuccessHandler执行时,会话里已经没有这个对象了,所以调用removeAuthorizationRequest会返回null。


解决方案一:自定义认证Provider,提前保存自定义参数

创建自定义的OAuth2LoginAuthenticationProvider,在默认认证逻辑执行前,把授权请求中的自定义参数存入Authentication对象的details中,这样在successHandler里就能直接获取:

1. 自定义认证Provider

public class CustomOAuth2LoginAuthenticationProvider extends OAuth2LoginAuthenticationProvider {
    private final OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;

    public CustomOAuth2LoginAuthenticationProvider(OAuth2AuthorizationService authorizationService,
                                                   OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository) {
        super(authorizationService);
        this.authorizationRequestRepository = authorizationRequestRepository;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        OAuth2LoginAuthenticationToken authToken = (OAuth2LoginAuthenticationToken) authentication;
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            return super.authenticate(authentication);
        }
        HttpServletRequest request = requestAttributes.getRequest();
        
        // 在默认逻辑移除前获取授权请求
        OAuth2AuthorizationRequest authRequest = this.authorizationRequestRepository.loadAuthorizationRequest(request);
        if (authRequest != null && authRequest.getAdditionalParameters() != null) {
            // 将自定义参数存入Authentication的details
            authToken.setDetails(authRequest.getAdditionalParameters());
        }
        
        // 执行默认认证流程(默认流程会移除授权请求)
        return super.authenticate(authentication);
    }
}

2. 注册自定义Provider到Security配置

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public OAuth2LoginAuthenticationProvider customOAuth2LoginAuthenticationProvider(
            OAuth2AuthorizationService authorizationService,
            OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository) {
        return new CustomOAuth2LoginAuthenticationProvider(authorizationService, authorizationRequestRepository);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customOAuth2LoginAuthenticationProvider(authorizationService(), authorizationRequestRepository()));
    }

    // 其他配置(authorizationRequestRepository、customAuthorizationRequestResolver等)
    @Bean
    public OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository() {
        return new HttpSessionOAuth2AuthorizationRequestRepository();
    }

    // ... 其他Bean配置
}

3. 在SuccessHandler中获取参数

@Component
public class OAuth2SuccessHandler implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException {
        OAuth2LoginAuthenticationToken oauthToken = (OAuth2LoginAuthenticationToken) authentication;
        Map<String, Object> additionalParams = (Map<String, Object>) oauthToken.getDetails();
        String redirectOrigin = (String) additionalParams.get("redirect_origin");
        
        // 处理跳转或返回逻辑
        response.sendRedirect(redirectOrigin + "/login-success");
    }
}

解决方案二:直接将自定义参数存入HttpSession

在自定义的AuthorizationRequestResolver中,提取自定义参数后直接存入HttpSession,跳过依赖OAuth2AuthorizationRequestRepository的步骤:

1. 修改自定义AuthorizationRequestResolver

public class CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
    private final OAuth2AuthorizationRequestResolver delegate;

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

    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
        OAuth2AuthorizationRequest authRequest = this.delegate.resolve(request);
        if (authRequest != null) {
            String redirectOrigin = request.getParameter("redirect_origin");
            if (redirectOrigin != null) {
                // 直接存入session
                request.getSession().setAttribute("redirect_origin", redirectOrigin);
                // 可选:同时添加到授权请求的附加参数中
                authRequest = OAuth2AuthorizationRequest.from(authRequest)
                        .additionalParameters(Map.of("redirect_origin", redirectOrigin))
                        .build();
            }
        }
        return authRequest;
    }

    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
        OAuth2AuthorizationRequest authRequest = this.delegate.resolve(request, clientRegistrationId);
        if (authRequest != null) {
            String redirectOrigin = request.getParameter("redirect_origin");
            if (redirectOrigin != null) {
                request.getSession().setAttribute("redirect_origin", redirectOrigin);
                authRequest = OAuth2AuthorizationRequest.from(authRequest)
                        .additionalParameters(Map.of("redirect_origin", redirectOrigin))
                        .build();
            }
        }
        return authRequest;
    }
}

2. 在SuccessHandler中获取参数

@Component
public class OAuth2SuccessHandler implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException {
        String redirectOrigin = (String) request.getSession().getAttribute("redirect_origin");
        // 用完后清理session
        request.getSession().removeAttribute("redirect_origin");
        
        // 处理跳转逻辑
        response.sendRedirect(redirectOrigin + "/login-success");
    }
}

内容的提问来源于stack exchange,提问作者Roeland Van Heddegem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 05:25:20