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

如何在Spring Boot3+Spring Security中存储OAuth登录用户数据至数据库

解决Spring Boot OAuth登录后用户信息存入数据库的问题

问题说明

使用Spring Boot对接Google、Github的OAuth登录,已成功获取登录信息,但尝试将Authentication.getPrincipal()直接转为自定义User实体时出现类型转换错误:

class org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser cannot be cast to class com.axis.springauthtest.entity.User

自定义User实体结构:

@Entity
@ToString
@Table(name = "users")
@NoArgsConstructor
@AllArgsConstructor
public class User {

    @Id
    private String id;

    private String name;
    private String email;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }
}

当前Security配置已实现OAuth登录成功回调,但未处理数据库存储逻辑。

解决方案

1. 创建用户数据访问层(Repository)

先定义Repository接口用于数据库操作:

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, String> {
    // 根据邮箱查询用户,判断是否已存在
    User findByEmail(String email);
}

2. 统一提取OAuth用户信息

OAuth登录后,Google返回DefaultOidcUser,Github返回DefaultOAuth2User,需统一提取核心信息:

import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import java.util.Map;

public class OAuthUserInfoExtractor {
    public static User extractUser(Object principal) {
        String id = null;
        String name = null;
        String email = null;

        if (principal instanceof DefaultOidcUser) {
            DefaultOidcUser oidcUser = (DefaultOidcUser) principal;
            Map<String, Object> attributes = oidcUser.getAttributes();
            id = "google_" + oidcUser.getName(); // 加前缀避免不同平台ID冲突
            name = (String) attributes.get("name");
            email = (String) attributes.get("email");
        } else if (principal instanceof DefaultOAuth2User) {
            DefaultOAuth2User oauth2User = (DefaultOAuth2User) principal;
            Map<String, Object> attributes = oauth2User.getAttributes();
            id = "github_" + attributes.get("id").toString(); // 加前缀避免冲突
            name = (String) attributes.get("name");
            email = (String) attributes.get("email");
        }

        return new User(id, name, email);
    }
}

3. 修改Security配置,实现数据库存储逻辑

注入UserRepository,在登录成功回调中处理用户保存/更新:

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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private UserRepository userRepository;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
                .oauth2Login(oauth2 -> oauth2
                        .successHandler(authenticationSuccessHandler())
                )
                .build();
    }

    private AuthenticationSuccessHandler authenticationSuccessHandler() {
        return (request, response, authentication) -> {
            System.out.println("Login Successful");
            // 提取OAuth用户信息
            User oAuthUser = OAuthUserInfoExtractor.extractUser(authentication.getPrincipal());
            // 检查用户是否已存在
            User existingUser = userRepository.findByEmail(oAuthUser.getEmail());
            if (existingUser == null) {
                userRepository.save(oAuthUser);
                System.out.println("新用户已存入数据库:" + oAuthUser);
            } else {
                // 更新用户信息(比如昵称)
                existingUser.setName(oAuthUser.getName());
                userRepository.save(existingUser);
                System.out.println("用户信息已更新:" + existingUser);
            }
            // 登录成功后跳转首页
            response.sendRedirect("/");
        };
    }
}

额外注意

  • Github邮箱问题:若用户设置邮箱私密,attributes.get("email")会返回null,需在OAuth授权时添加user:email权限,再调用Github APIhttps://api.github.com/user/emails获取邮箱。
  • ID唯一性:给不同平台的用户ID添加前缀(如google_、github_),避免不同平台用户ID重复导致主键冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 15:27:01