Keycloak与Springboot/Vaadin SSO集成后UI.navigate跳转异常问题
解决Vaadin从匿名页面导航到受保护页面不跳转登录的问题
直接访问路由时权限校验正常,但通过UI.navigate()从匿名页面跳转至带@PermitAll的受保护页面时报错,核心原因是Vaadin客户端导航默认不会触发服务端的权限拦截逻辑——直接访问是服务端处理请求,会触发Keycloak的登录重定向;而客户端跳转是通过前端XHR请求加载视图,跳过了服务端的权限校验步骤,导致因权限不足无法加载视图,进而抛出导航失败的错误。
解决方案:全局导航权限拦截
通过实现Vaadin的BeforeEnterObserver接口,在导航触发前统一校验目标页面的权限,未认证时主动重定向到Keycloak登录页。
1. 编写全局导航拦截器
创建一个UI作用域的拦截器,在每次导航前检查目标视图的权限注解:
@Component @UIScope public class AuthNavigationInterceptor implements BeforeEnterObserver { @Override public void beforeEnter(BeforeEnterEvent event) { Class<?> targetView = event.getNavigationTarget(); // 检查目标视图是否需要授权访问 if (targetView.isAnnotationPresent(PermitAll.class)) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); // 判断用户是否未认证(匿名用户) if (auth == null || !auth.isAuthenticated() || "anonymousUser".equals(auth.getPrincipal())) { // 重定向到Keycloak登录端点(根据你的配置调整路径) String loginUrl = "/oauth2/authorization/keycloak"; event.rerouteTo(loginUrl); event.preventDefault(); // 阻止原导航请求 } } } }
2. 确保Spring Security配置正确
检查你的Security配置,确保Vaadin的核心路径被正确处理,同时Keycloak的登录流程正常:
@Configuration @EnableWebSecurity public class SecurityConfig extends VaadinWebSecurity { @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); // 配置Keycloak OAuth2登录 http.oauth2Login() .loginPage("/oauth2/authorization/keycloak"); // 确保所有请求都经过权限校验(除了静态资源) http.authorizeHttpRequests() .requestMatchers("/VAADIN/**", "/favicon.ico", "/images/**", "/styles/**").permitAll() .anyRequest().authenticated(); } }
原理说明
BeforeEnterObserver是Vaadin提供的导航生命周期钩子,会在每次导航(包括客户端跳转)触发前执行,能在服务端提前拦截未授权的导航请求。- 通过校验目标视图的
@PermitAll注解,结合Spring Security的认证状态,判断是否需要重定向登录,确保客户端跳转和直接访问的权限逻辑一致。
内容的提问来源于stack exchange,提问作者Sebastian Olscher
相关产品推荐
相关产品推荐

