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

Spring OAuth2 SSO异常:无令牌仍可登录且注销后自动登录

解决Spring OAuth2 SSO注销后自动重登的问题

我之前也踩过OAuth2 SSO注销的坑,你的问题核心其实是注销操作只清理了授权服务器的令牌,但没处理SSO服务和授权服务的本地会话,也没同步清理浏览器端的认证Cookie,咱们一步步来解决:

问题拆解

  • 注销后MongoDB令牌已清除,但刷新SSO页面自动登录:这是因为SSO服务器(@EnableOAuth2Sso)自己维护了用户登录会话,只要本地Session还在,它会自动尝试重新获取令牌,甚至直接认为用户已登录。
  • 授权服务器无令牌时SSO仍能登录:大概率是授权服务器的用户认证会话(比如登录时生成的Session)没失效,SSO跳转去授权时,授权服务器直接复用了旧会话完成认证。

具体解决方案

1. 清理SSO服务器的本地会话

在你的SSO注销端点里,除了调用授权服务器的令牌清除接口,一定要手动失效当前的HttpSession,同时清理浏览器端的SSO Cookie:

@GetMapping("/logout")
public String logout(HttpServletRequest request, HttpServletResponse response) {
    // 1. 调用授权服务器的令牌撤销接口
    String accessToken = (String) request.getSession().getAttribute("access_token");
    if (accessToken != null) {
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(accessToken);
        restTemplate.postForObject("http://auth-server/oauth/revoke-token", headers, Void.class);
    }

    // 2. 失效SSO服务器的本地会话
    request.getSession().invalidate();
    SecurityContextHolder.clearContext();

    // 3. 清理浏览器端的JSESSIONID Cookie
    Cookie sessionCookie = new Cookie("JSESSIONID", null);
    sessionCookie.setMaxAge(0);
    sessionCookie.setPath("/");
    response.addCookie(sessionCookie);

    // 4. 重定向到授权服务器的注销页面,同步清理其会话
    return "redirect:http://auth-server/logout?redirect_uri=http://sso-server/login";
}

2. 让授权服务器同步清理认证会话

授权服务器(@EnableAuthorizationServer)需要提供一个注销端点,不仅清除令牌,还要失效自身的登录Session:

@GetMapping("/logout")
public String logout(HttpServletRequest request, @RequestParam String redirect_uri) {
    // 1. 根据当前登录用户清除所有关联令牌
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth != null) {
        // 从tokenStore中查询并删除该用户的所有access_token和refresh_token
        RefreshToken refreshToken = tokenStore.findRefreshTokenByUsername(auth.getName());
        if (refreshToken != null) {
            tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);
            tokenStore.removeRefreshToken(refreshToken);
        }
    }

    // 2. 失效授权服务器的本地会话
    request.getSession().invalidate();
    SecurityContextHolder.clearContext();

    // 3. 清理浏览器端的授权服务器Cookie
    Cookie authSessionCookie = new Cookie("JSESSIONID", null);
    authSessionCookie.setMaxAge(0);
    authSessionCookie.setPath("/");
    response.addCookie(authSessionCookie);

    // 4. 重定向回SSO的登录页面
    return "redirect:" + redirect_uri;
}

3. 强化SSO服务器的会话验证

在SSO的Security配置中,强制会话失效后跳转登录页,并且每次请求都验证令牌有效性,避免依赖本地Session直接登录:

@Configuration
@EnableOAuth2Sso
public class SsoSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .sessionManagement()
                .invalidSessionUrl("/login") // 会话失效后强制跳登录页
                .maximumSessions(1) // 限制单用户单会话,避免旧会话残留
                .and()
            .oauth2Client()
                .userInfoEndpoint()
                .userService(customUserInfoService); // 自定义用户信息服务,每次请求验证令牌有效性
    }
}

总结

注销操作必须是全链路的清理:授权服务器的令牌 + 授权服务器的登录会话 + SSO服务器的本地会话 + 浏览器端的认证Cookie,缺了任何一环都会出现自动重登的问题。按上面的步骤调整后,应该就能解决你的问题了。

内容的提问来源于stack exchange,提问作者J. Leander

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:27:09