You need to enable JavaScript to run this app. Spring Security结合Keycloak:公开页面无跳转校验用户登录态
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security结合Keycloak:公开页面无跳转校验用户登录态

Spring Security整合Keycloak场景下公开页的已登录状态校验方案

核心目标

实现公开页面在不触发强制登录跳转、不要求用户提前访问受保护资源的前提下,精准识别已在Keycloak完成SSO认证的用户,为页面头部动态渲染专属内容。

具体实现路径

1. 重构Spring Security的路由鉴权规则

  • 将所有公开可访问的页面路径配置为permitAll(),不对该类路径的未认证访问做拦截
  • 覆盖Spring Security默认的未认证跳转逻辑:仅当用户访问受保护资源触发鉴权失败时,才重定向到Keycloak的登录流程;访问公开路径时即使未认证,也直接放行,不触发任何跳转
  • 配置示例:
@Bean
public SecurityFilterChain keycloakSecurityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(registry -> registry
            // 公开页面路径完全放行
            .requestMatchers("/public/**", "/assets/**").permitAll()
            // 其余路径走正常Keycloak鉴权
            .anyRequest().authenticated()
        )
        .oauth2Login(Customizer.withDefaults())
        // 自定义未认证处理逻辑,避免全局强制跳转
        .exceptionHandling(handler -> handler
            .authenticationEntryPoint((request, response, authException) -> {
                // 公开路径的请求,鉴权失败时直接返回正常响应,不跳转
                if (request.getRequestURI().startsWith("/public/")) {
                    response.setStatus(HttpServletResponse.SC_OK);
                    response.setContentType("text/html;charset=utf-8");
                    return;
                }
                // 受保护路径的请求,走原有Keycloak登录跳转逻辑
                response.sendRedirect("/oauth2/authorization/keycloak");
            })
        );
    return http.build();
}

2. 搭建轻量的静默状态校验接口

  • 专门暴露一个无跳转的状态查询接口,比如路径/api/public/auth-status,该接口的权限规则为permitAll(),无论用户是否认证都可以访问
  • 接口内部直接复用Spring Security的上下文能力校验当前请求的认证状态:
    • 从SecurityContextHolder中读取已解析的认证对象,判断当前请求是否携带有效的Keycloak会话/凭证
    • 若凭证有效,直接提取用户基础信息返回给前端,无需触发额外的Keycloak认证流程
    • 若凭证无效,直接返回未登录标识,不做任何重定向、token刷新等打断性操作
  • 接口实现示例:
@RestController
public class PublicAuthStatusController {
    @GetMapping("/api/public/auth-status")
    public Map<String, Object> getLoginStatus() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        // 匿名状态直接返回未登录标识
        if (auth == null || !auth.isAuthenticated() 
            || auth instanceof AnonymousAuthenticationToken) {
            return Map.of("isLoggedIn", false);
        }
        // 已登录状态返回页面头部需要的用户信息
        KeycloakPrincipal principal = (KeycloakPrincipal) auth.getPrincipal();
        return Map.of(
            "isLoggedIn", true,
            "username", principal.getKeycloakSecurityContext().getToken().getPreferredUsername(),
            "displayName", principal.getKeycloakSecurityContext().getToken().getName()
        );
    }
}

3. 前端公开页的适配逻辑

  • 页面头部组件挂载完成后,异步发起对/api/public/auth-status的请求
  • 根据接口返回结果动态渲染内容:
    • 返回已登录状态时,展示用户专属的头部入口、用户信息等内容
    • 返回未登录状态时,展示通用的公开导航栏
  • 整个校验过程全程异步,不阻塞页面渲染,也不触发任何页面跳转

常见注意事项

  • 配置Keycloak adapter的Cookie作用域时,要保证公开页面所在域名下的后端服务能正常读取Keycloak的SSO会话Cookie,避免出现“明明已在Keycloak登录但校验接口判定未登录”的问题
  • 不要在静默校验接口中主动触发token刷新、Keycloak登录弹窗等交互逻辑,如果用户的Keycloak会话已经过期,就直接返回未登录状态,避免打断公开页的浏览体验
  • 不要直接拿受保护资源的路径做校验触发器,否则访问受保护路径时会触发默认的登录跳转逻辑,违背“不提前进入登录流程”的要求

内容的提问来源于stack exchange,提问作者Łukasz Bryniarski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 09:36:06