Spring Boot Security集成OAuth2/OIDC后获取用户信息如何恢复原有本地认证
问题根因
你当前使用的oauth2Login是Spring Security专为第三方登录场景设计的能力,默认会用OAuth2返回的身份信息覆盖SecurityContext中存储的本地登录认证,同时默认的会话固定防护策略会重置sessionId,导致原有会话失效,所以用户回调后会变为匿名状态,和你仅获取远程服务用户属性、保留本地登录态的需求完全不匹配。
解决方案
方案一:改用OAuth2客户端模式(推荐)
直接使用Spring Security OAuth2客户端的授权码流程,完全不触发登录逻辑,不会修改原有用户身份:
- 修改
OAuth2LoginSecurityConfig配置,替换oauth2Login为oauth2Client:
@Override protected void configure(HttpSecurity http) throws Exception { http .antMatcher("/identity/**") .authorizeRequests() .anyRequest().authenticated() .and() // 仅启用OAuth2客户端能力,不做登录认证 .oauth2Client() .authorizationEndpoint() .baseUri("/identity/oauth2/authorization") .authorizationRequestResolver( new CustomOAuth2AuthorizationRequestResolver( clientRegistrationRepository, "/identity/oauth2/authorization" )) .and() .redirectionEndpoint() .baseUri("/identity/oauth2/code/srvdev"); }
- 新增控制器自行处理回调逻辑,直接获取令牌和用户属性:
@GetMapping("/identity/oauth2/code/srvdev") public String handleOidcCallback( @RegisteredOAuth2AuthorizedClient("你的客户端注册ID") OAuth2AuthorizedClient authorizedClient, Authentication localAuth ) { // 直接获取令牌和用户信息 OidcIdToken idToken = ((OidcUser) authorizedClient.getPrincipal()).getIdToken(); String accessToken = authorizedClient.getAccessToken().getTokenValue(); // 自行调用userInfo端点获取额外属性,处理你的业务逻辑 // localAuth就是用户原本的本地登录认证信息,完全未被修改 // 处理完成直接跳转到业务页面即可 return "redirect:/your-business-path"; }
方案二:保留现有oauth2Login配置,自定义逻辑恢复原有认证
如果不想调整现有流程,可以通过自定义处理器恢复本地登录态:
- 新增拦截器,在跳转OAuth授权页前存储原有认证:
@Component public class SaveOriginalAuthInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken)) { request.getSession().setAttribute("ORIGINAL_SECURITY_CONTEXT", SecurityContextHolder.getContext()); } return true; } }
注册拦截器到Spring MVC,匹配路径/identity/oauth2/authorization。
2. 自定义OAuth2登录成功处理器,恢复原有认证:
@Override protected void configure(HttpSecurity http) throws Exception { http .antMatcher("/identity/**") .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .sessionFixation().none() // 禁用sessionId重置,避免原有会话失效 .and() .authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login() .successHandler(new AuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication oauthAuth) throws IOException, ServletException { // 提取OAuth2返回的ID Token、用户属性,处理你的业务逻辑 OidcUser oidcUser = (OidcUser) oauthAuth.getPrincipal(); // 恢复原有本地认证 HttpSession session = request.getSession(false); if (session != null) { SecurityContext originalContext = (SecurityContext) session.getAttribute("ORIGINAL_SECURITY_CONTEXT"); if (originalContext != null) { SecurityContextHolder.setContext(originalContext); session.removeAttribute("ORIGINAL_SECURITY_CONTEXT"); } } // 跳转到指定页面 response.sendRedirect("/identity/success"); } }) // 剩下的原有配置保持不变 .loginPage("/identity") .authorizationEndpoint() // 其余原有配置无需修改 ... }
内容的提问来源于stack exchange,提问作者grant
相关产品推荐
相关产品推荐

