Spring OAuth2登录存储问题:Google登录后如何自动保存client-id?
The core issue here is that your current storage logic is tied to the /user endpoint, which users might never hit after logging in. To fix this, we need to trigger the client-id storage immediately when a user completes Google OAuth authentication, rather than waiting for them to access a specific API endpoint.
Here's how to implement this step-by-step, using your existing OAuthSecurityConfig.java and adapting the logic from UserRestController.java:
1. Create a Custom OAuth2 Login Success Handler
This handler will run automatically right after a user successfully logs in with Google. We'll move your client-id storage logic here.
@Component public class GoogleOAuth2LoginSuccessHandler implements AuthenticationSuccessHandler { private final UserRepository userRepository; // Inject your existing user repository // Constructor injection (Spring will handle this if you're using component scanning) public GoogleOAuth2LoginSuccessHandler(UserRepository userRepository) { this.userRepository = userRepository; } @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { // Extract OAuth2 user details from the Authentication object if (authentication instanceof OAuth2AuthenticationToken oAuth2Token) { OAuth2User oAuth2User = oAuth2Token.getPrincipal(); // Fetch the client-id (adjust the attribute key based on what's in your Principal object) // For Google OAuth, the unique user ID is typically stored under the "sub" attribute String userClientId = oAuth2User.getAttribute("sub"); // Reuse your existing storage logic: check if the user already exists, then save if not if (!userRepository.existsByClientId(userClientId)) { User newUser = new User(); newUser.setClientId(userClientId); // Optional: Add other user details from the OAuth2 attributes newUser.setEmail(oAuth2User.getAttribute("email")); newUser.setDisplayName(oAuth2User.getAttribute("name")); userRepository.save(newUser); } } // Redirect the user to your desired post-login page (e.g., homepage) response.sendRedirect("/"); } }
2. Update OAuthSecurityConfig.java to Use the Custom Handler
Wire up your new success handler in the security configuration so it replaces the default OAuth2 login success behavior:
@Configuration @EnableWebSecurity public class OAuthSecurityConfig extends WebSecurityConfigurerAdapter { private final GoogleOAuth2LoginSuccessHandler loginSuccessHandler; public OAuthSecurityConfig(GoogleOAuth2LoginSuccessHandler loginSuccessHandler) { this.loginSuccessHandler = loginSuccessHandler; } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login() .successHandler(loginSuccessHandler); // Attach our custom handler here } }
3. Clean Up UserRestController.java
You can now remove the storage logic from the /user endpoint (since it's no longer needed), or leave it in place as a fallback if you still want to allow manual triggering:
@RestController @RequestMapping("/user") public class UserRestController { private final UserRepository userRepository; public UserRestController(UserRepository userRepository) { this.userRepository = userRepository; } @GetMapping public Principal getUser(Principal principal) { // Optional: Keep this if you still want to return user details, but remove the storage code return principal; } }
Key Notes:
- Adjust the attribute key: Make sure
oAuth2User.getAttribute("sub")matches the actual key for the client-id in your Principal object. If you're referring to the OAuth client's ID (not the user's unique ID), useoAuth2Token.getAuthorizedClientRegistrationId()instead. - Avoid duplicate saves: The
existsByClientIdcheck ensures you don't create duplicate user records on every login. - Post-login redirect: Customize the
response.sendRedirect("/")line to send users to whatever page makes sense for your application.
This approach ensures the client-id is stored the moment a user logs in, no matter what they do next—no need to rely on them accessing the /user endpoint.
内容的提问来源于stack exchange,提问作者Gabrielus

