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

如何在Spring Boot OAuth2Client中获取authToken、oauth2User并关联自有用户

Spring Boot 3.4 实现已登录用户绑定第三方OAuth2平台并保存令牌

核心思路

利用Spring Security OAuth2 Client的授权成功回调节点,在第三方平台授权完成后,获取令牌、第三方用户信息,同时关联当前已登录的自有用户,将关联数据持久化到数据库。

步骤实现

1. 配置OAuth2客户端注册

在application.yml中配置需要绑定的第三方平台(如Dropbox、Google),每个平台使用唯一的registration id区分:

spring:
  security:
    oauth2:
      client:
        registration:
          dropbox:
            client-id: your-dropbox-client-id
            client-secret: your-dropbox-client-secret
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/dropbox"
            scope: files.content.read,files.content.write
          google:
            client-id: your-google-client-id
            client-secret: your-google-client-secret
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/google"
            scope: email,profile,drive.readonly
        provider:
          dropbox:
            authorization-uri: https://www.dropbox.com/oauth2/authorize
            token-uri: https://api.dropboxapi.com/oauth2/token
            user-info-uri: https://api.dropboxapi.com/2/users/get_current_account
            user-name-attribute: account_id

2. 自定义授权成功处理器

创建CustomOAuth2AuthorizationSuccessHandler,继承SimpleOAuth2AuthorizationSuccessHandler,在授权成功时获取令牌、第三方用户信息,并关联当前自有用户:

@Component
public class CustomOAuth2AuthorizationSuccessHandler extends SimpleOAuth2AuthorizationSuccessHandler {

    private final UserOAuth2ConnectionRepository connectionRepository;

    public CustomOAuth2AuthorizationSuccessHandler(UserOAuth2ConnectionRepository connectionRepository) {
        this.connectionRepository = connectionRepository;
        // 设置授权成功后的跳转页面,比如回到用户绑定中心
        setTargetUrlParameter("redirect_uri");
        setDefaultTargetUrl("/user/connections");
    }

    @Override
    public void onAuthorizationSuccess(OAuth2AuthorizationRequest authorizationRequest,
                                       OAuth2AccessToken accessToken,
                                       OAuth2AuthenticationToken authentication,
                                       HttpServletRequest request,
                                       HttpServletResponse response) throws ServletException, IOException {
        // 获取当前已登录的自有用户
        Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
        YourUserEntity ownUser = (YourUserEntity) currentUser.getPrincipal();

        // 获取第三方平台标识(即registration id)
        String clientRegistrationId = authentication.getAuthorizedClientRegistrationId();
        // 获取第三方用户信息
        OAuth2User oAuth2User = authentication.getPrincipal();
        String thirdPartyUserId = oAuth2User.getName();

        // 构建关联实体,保存令牌等信息
        UserOAuth2Connection connection = new UserOAuth2Connection();
        connection.setUserId(ownUser.getId());
        connection.setClientRegistrationId(clientRegistrationId);
        connection.setThirdPartyUserId(thirdPartyUserId);
        connection.setAccessToken(accessToken.getTokenValue());
        connection.setRefreshToken(accessToken.getRefreshToken() != null ? accessToken.getRefreshToken().getTokenValue() : null);
        connection.setExpiresAt(accessToken.getExpiresAt());
        connection.setScopes(String.join(",", accessToken.getScopes()));

        // 保存到数据库,可先判断是否已存在绑定关系,存在则更新
        connectionRepository.save(connection);

        // 调用父类方法完成跳转
        super.onAuthorizationSuccess(authorizationRequest, accessToken, authentication, request, response);
    }
}

3. 配置SecurityFilterChain

将自定义处理器关联到OAuth2 Client流程,同时确保授权端点仅对已登录用户开放:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final CustomOAuth2AuthorizationSuccessHandler authorizationSuccessHandler;
    private final CustomOAuth2UserService customOAuth2UserService;

    public SecurityConfig(CustomOAuth2AuthorizationSuccessHandler authorizationSuccessHandler,
                          CustomOAuth2UserService customOAuth2UserService) {
        this.authorizationSuccessHandler = authorizationSuccessHandler;
        this.customOAuth2UserService = customOAuth2UserService;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/dashboard")
            )
            .oauth2Login(oauth2 -> oauth2
                .userInfoEndpoint(userInfo -> userInfo
                    .userService(customOAuth2UserService)
                )
            )
            .oauth2Client(oauth2 -> oauth2
                .authorizationCodeGrant(codeGrant -> codeGrant
                    .authorizationSuccessHandler(authorizationSuccessHandler)
                )
            )
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/oauth2/authorization/**").authenticated()
                .anyRequest().authenticated()
            );

        return http.build();
    }
}

4. 持久化实体与Repository

创建关联实体类和Repository,用于存储用户与第三方平台的绑定关系:

@Entity
@Table(name = "user_oauth2_connections")
public class UserOAuth2Connection {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "user_id", nullable = false)
    private Long userId;

    @Column(name = "client_registration_id", nullable = false)
    private String clientRegistrationId;

    @Column(name = "third_party_user_id", nullable = false)
    private String thirdPartyUserId;

    @Column(name = "access_token", nullable = false)
    private String accessToken;

    @Column(name = "refresh_token")
    private String refreshToken;

    @Column(name = "expires_at")
    private Instant expiresAt;

    @Column(name = "scopes")
    private String scopes;

    // getter、setter、构造方法省略
}

public interface UserOAuth2ConnectionRepository extends JpaRepository<UserOAuth2Connection, Long> {
    Optional<UserOAuth2Connection> findByUserIdAndClientRegistrationId(Long userId, String clientRegistrationId);
}

5. 前端触发绑定操作

在用户中心页面添加绑定按钮,链接到对应平台的OAuth2授权端点:

<!-- Dropbox绑定按钮 -->
<a href="/oauth2/authorization/dropbox?redirect_uri=/user/connections">绑定Dropbox</a>

<!-- Google绑定按钮 -->
<a href="/oauth2/authorization/google?redirect_uri=/user/connections">绑定Google</a>

关键说明

  • 该方案基于Spring Security原生扩展点,更换第三方平台仅需修改application.yml中的客户端配置,无需改动核心代码,符合可扩展要求。
  • 若需要处理令牌过期自动刷新,可结合OAuth2AuthorizedClientService在调用第三方API前检查令牌状态,触发刷新逻辑。
  • 第三方用户信息的解析可根据不同平台的返回结构,在onAuthorizationSuccess方法中灵活提取所需字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:55:18