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

如何在Spring Security中为联邦认证动态配置userInfoUri和tokenUri

动态调整OAuth2 Client的tokenUri和userInfoUri方案

可以实现根据授权码动态修改tokenUri和userInfoUri的需求,但要注意**ClientRegistration是不可变类**,无法直接修改已创建实例的属性,需要通过以下几种方式实现动态调整:

方案一:自定义ClientRegistrationRepository

放弃使用固定的InMemoryClientRegistrationRepository,自定义实现类,在每次获取ClientRegistration时根据当前请求的授权码动态生成对应URI:

@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
    return new ClientRegistrationRepository() {
        @Override
        public ClientRegistration findByRegistrationId(String registrationId) {
            // 从当前请求上下文获取授权码
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String authCode = request.getParameter("code");

            // 根据授权码动态生成tokenUri和userInfoUri
            String dynamicTokenUri = buildTokenUri(authCode);
            String dynamicUserInfoUri = buildUserInfoUri(authCode);

            return ClientRegistration
                    .withRegistrationId("project")
                    .clientId("clientid")
                    .clientSecret("clientsecret")
                    .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                    .redirectUri(redirectUri)
                    .scope(Arrays.asList(scope.split(",")))
                    .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                    .authorizationUri(authorizationURI)
                    .tokenUri(dynamicTokenUri)
                    .userInfoUri(dynamicUserInfoUri)
                    .userNameAttributeName(userNameAttributes)
                    .build();
        }
    };
}

// 自定义生成URI的逻辑方法
private String buildTokenUri(String authCode) {
    // 根据授权码拼接或获取对应的token地址
    return "https://example.com/token?code=" + authCode;
}

private String buildUserInfoUri(String authCode) {
    // 根据授权码拼接或获取对应的用户信息地址
    return "https://example.com/userinfo?code=" + authCode;
}

注意:要确保RequestContextHolder能正确获取当前请求上下文,在异步场景下可能需要额外处理线程绑定。

方案二:针对特定流程自定义客户端/服务类

如果不需要全局替换ClientRegistration,可以针对token请求和用户信息请求分别自定义处理逻辑:

1. 动态修改tokenUri(自定义TokenResponseClient)

@Bean
public OAuth2AuthorizationCodeTokenResponseClient tokenResponseClient() {
    DefaultAuthorizationCodeTokenResponseClient tokenClient = new DefaultAuthorizationCodeTokenResponseClient();
    tokenClient.setRestOperations(new RestTemplate() {
        @Override
        public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables) {
            // 从授权请求中提取授权码
            OAuth2AuthorizationCodeGrantTokenRequest tokenRequest = (OAuth2AuthorizationCodeGrantTokenRequest) request;
            String authCode = tokenRequest.getAuthorizationExchange().getAuthorizationResponse().getCode();
            
            // 替换为动态生成的tokenUri
            String dynamicTokenUri = buildTokenUri(authCode);
            return super.postForObject(dynamicTokenUri, request, responseType, uriVariables);
        }
    });
    return tokenClient;
}

2. 动态修改userInfoUri(自定义OAuth2UserService)

@Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
    DefaultOAuth2UserService userService = new DefaultOAuth2UserService();
    userService.setRestOperations(new RestTemplate() {
        @Override
        public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) {
            // 从请求上下文获取OAuth2UserRequest,进而提取授权码
            OAuth2UserRequest userRequest = (OAuth2UserRequest) RequestContextHolder.getRequestAttributes()
                    .getAttribute("oauth2UserRequest", RequestAttributes.SCOPE_REQUEST);
            String authCode = userRequest.getAuthorizationExchange().getAuthorizationResponse().getCode();
            
            // 替换为动态生成的userInfoUri
            String dynamicUserInfoUri = buildUserInfoUri(authCode);
            return super.getForObject(dynamicUserInfoUri, responseType, uriVariables);
        }
    });
    return userService;
}

关键注意事项

  • 授权码的获取逻辑需根据实际流程调整:在授权回调阶段,code直接从请求参数获取;在后续token/userInfo请求阶段,需从OAuth2上下文对象中提取。
  • 确保动态生成URI的逻辑线程安全,避免并发场景下的参数混乱。
  • 适配Spring Security版本:上述代码基于Spring Security 5.x+,不同版本的类/接口可能存在差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 11:01:31