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

如何在含双Vue前端的应用中使用多Keycloak实例与上下文?

我之前刚好帮团队解决过几乎一模一样的多Keycloak上下文共存问题,针对你的Vue+Java架构,给你拆解几个关键的实现步骤:

一、在Vue中初始化完全独立的Keycloak实例

首先要明确:两个前端必须使用完全独立的Keycloak实例,绝对不能共用同一个Keycloak对象。

  • 为两个前端分别编写Keycloak配置文件,比如keycloak-public.js(公开前端)和keycloak-internal.js(内部前端),各自填入对应的Keycloak服务地址、Realm、Client ID:
// keycloak-public.js(公开前端)
import Keycloak from 'keycloak-js'
export const keycloakPublic = new Keycloak({
  url: 'https://your-public-keycloak-domain/auth',
  realm: 'public-realm',
  clientId: 'public-frontend-client'
})
  • 在各自的Vue项目入口(或模块入口)中独立初始化实例,挂载到Vue全局时使用不同命名(比如$keycloakPublic和$keycloakInternal),避免互相覆盖:
// 公开前端main.js
import { keycloakPublic } from './utils/keycloak-public'
async function initApp() {
  await keycloakPublic.init({
    onLoad: 'login-required',
    redirectUri: window.location.origin
  })
  const app = createApp(App)
  app.config.globalProperties.$keycloak = keycloakPublic
  app.mount('#app')
}
initApp()

二、隔离认证状态的存储(核心解决冲突)

默认情况下,Keycloak-js会用localStorage/sessionStorage存储token,两个实例用相同键名会互相覆盖,导致认证状态混乱。解决办法是给每个实例配置自定义存储键:

  • 自定义Keycloak的存储适配器,指定不同的键前缀:
// 内部前端初始化时添加adapter配置
await keycloakInternal.init({
  onLoad: 'check-sso',
  adapter: {
    getToken: () => sessionStorage.getItem('internal-access-token'),
    setToken: (token) => sessionStorage.setItem('internal-access-token', token),
    getRefreshToken: () => sessionStorage.getItem('internal-refresh-token'),
    setRefreshToken: (token) => sessionStorage.setItem('internal-refresh-token', token),
    getIdToken: () => sessionStorage.getItem('internal-id-token'),
    setIdToken: (token) => sessionStorage.setItem('internal-id-token', token),
    clearToken: () => {
      sessionStorage.removeItem('internal-access-token')
      sessionStorage.removeItem('internal-refresh-token')
      sessionStorage.removeItem('internal-id-token')
    }
  }
})

这样两个前端的认证token会存在不同的存储键下,完全不会互相干扰。

三、独立控制路由守卫和认证逻辑

两个前端的路由守卫要分别绑定各自的Keycloak实例,不要混用:

  • 公开前端的路由守卫示例:
router.beforeEach(async (to, from, next) => {
  const keycloak = router.app.config.globalProperties.$keycloakPublic
  if (to.meta.requiresAuth) {
    if (!keycloak.authenticated) {
      await keycloak.login({ redirectUri: window.location.origin + to.fullPath })
    } else {
      // 可选:自动刷新过期token
      if (keycloak.isTokenExpired()) {
        await keycloak.updateToken(5)
      }
      next()
    }
  } else {
    next()
  }
})

内部前端的路由守卫同理,只需替换为$keycloakInternal实例即可。

四、Java后端的配合处理

因为两个Keycloak是独立的,Java后端需要能验证来自不同Keycloak的token:

  • 在Spring Boot后端中配置两个独立的Keycloak认证提供者,分别对应公开和内部Keycloak的Realm公钥:
// 公开接口的认证配置
@Bean
public KeycloakAuthenticationProvider publicKeycloakAuthProvider() {
  KeycloakAuthenticationProvider provider = new KeycloakAuthenticationProvider();
  provider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
  return provider;
}

// 内部接口的认证配置
@Bean
public KeycloakAuthenticationProvider internalKeycloakAuthProvider() {
  KeycloakAuthenticationProvider provider = new KeycloakAuthenticationProvider();
  provider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
  return provider;
}
  • 针对不同的接口路径绑定不同的认证过滤器,比如/public/**对应公开Keycloak认证,/internal/**对应内部Keycloak认证。

最后测试验证

完成配置后,可以通过以下步骤验证:

  1. 打开公开前端完成登录,查看浏览器存储中是否有带public-前缀的token;
  2. 打开内部前端访问需认证页面,会跳转到内部Keycloak登录页,登录后存储中会出现带internal-前缀的token;
  3. 此时两个前端的认证状态完全独立,不会互相影响。

内容的提问来源于stack exchange,提问作者Anothereno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 16:58:12