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

OIDC Client集成WSO2 APIM 3.2.0 iframe跨标签登出失效问题

Angular集成WSO2 API Manager 3.2.0 OIDC跨标签页同步登出修复

问题概述

Angular应用通过OIDC Client对接WSO2 API Manager 3.2.0实现身份认证,除登出流程外其余功能正常。

复现步骤

  • 单浏览器标签页完成应用登录,登录成功后复制该标签页
  • 在其中一个标签页执行登出操作,预期其余复制标签页同步完成登出,实际未触发同步登出逻辑
  • 刷新复制出的标签页时,页面跳转至错误地址:https://localhost:9443/authenticationendpoint/oauth2_error.do?oauthErrorCode=access_denied&oauthErrorMsg=Error+occurred+while+extracting+data+from+id+token,标签页无法自动触发登出

现有问题实现

TypeScript 代码

baseUrl = new URL(window.location.href);
  callbackURI = this.baseUrl.origin + '/slate/dashboard';

  checkSessionURL = this.sanitizer.bypassSecurityTrustResourceUrl('https://localhost:9443/oidc/checksession' + '?client_id='
            + localStorage.getItem('client_id') + '&redirect_uri=' + this.callbackURI);

  constructor(private sanitizer: DomSanitizer, private authService: AuthService) {
  }

  ngOnInit(): void {
  }

  ngAfterViewInit(): void {
    if (this.authService.isLoggedUser()) {
      this.checkSession();
    }
  }

  isIFrame = (input: HTMLElement | null): input is HTMLIFrameElement =>
    input !== null && input.tagName === 'IFRAME'

  /**
   * Invoke check session OIDC endpoint.
   */
  checkSession(): void {
    setInterval(() => {
      const msg = localStorage.getItem('client_id') + ' ' + localStorage.getItem('sessionState');
      const frame = document.getElementById('iframeOP');
      if (this.isIFrame(frame) && frame.contentWindow) {
        frame.contentWindow.postMessage(msg, 'https://localhost:9443/oidc/checksession');
      }
    }, 3000);
  }

HTML 模板代码

<iframe
  title='iframeOP'
  id='iframeOP'
  [src]="checkSessionURL"
></iframe>

故障根因

  • 现有会话检查逻辑仅向OP iframe发送postMessage,未绑定消息监听接收OP返回的会话状态,无法感知会话变更触发登出
  • Check Session端点URL参数未做编码,iframe未配置必要的沙箱权限,导致WSO2侧参数解析失败、跨域通信异常
  • 未利用浏览器同域storage事件做跨标签页状态同步兜底,状态感知延迟高
  • 本地登出逻辑未完整清理失效的OIDC凭证,刷新页面时携带无效id_token请求WSO2,触发id_token解析错误

修复方案

1. 补全Check Session消息监听逻辑

新增OP消息监听,收到会话变更、错误状态时立刻触发本地登出,同时在组件销毁时清理定时器、解绑事件避免内存泄漏:

// 新增类属性
private sessionCheckTimer?: number;
private sessionCheckListener?: (e: MessageEvent) => void;
private storageListener?: (e: StorageEvent) => void;

ngAfterViewInit(): void {
  if (this.authService.isLoggedUser()) {
    this.bindSessionCheckListener();
    this.bindStorageSyncListener();
    this.checkSession();
  }
}

ngOnDestroy(): void {
  if (this.sessionCheckTimer) clearInterval(this.sessionCheckTimer);
  if (this.sessionCheckListener) window.removeEventListener('message', this.sessionCheckListener);
  if (this.storageListener) window.removeEventListener('storage', this.storageListener);
}

/**
 * 绑定OP会话状态消息监听
 */
bindSessionCheckListener(): void {
  this.sessionCheckListener = (e: MessageEvent) => {
    // 过滤非WSO2来源的非法消息
    if (e.origin !== 'https://localhost:9443') return;
    const res = e.data?.trim();
    // 会话变更/校验失败时触发本地登出
    if (res === 'changed' || res === 'error') {
      this.authService.logoutLocal();
    }
  };
  window.addEventListener('message', this.sessionCheckListener);
}

2. 修正Iframe与Check Session URL配置

对URL参数做编码,给iframe添加必要沙箱权限,同时隐藏iframe避免影响页面布局:

<iframe
  title='iframeOP'
  id='iframeOP'
  [src]="checkSessionURL"
  sandbox="allow-scripts allow-same-origin"
  style="display: none;"
></iframe>

修正TS中Check Session URL的拼接逻辑,避免特殊字符导致参数解析失败:

const clientId = encodeURIComponent(localStorage.getItem('client_id') || '');
const redirectUri = encodeURIComponent(this.callbackURI);
this.checkSessionURL = this.sanitizer.bypassSecurityTrustResourceUrl(
  `https://localhost:9443/oidc/checksession?client_id=${clientId}&redirect_uri=${redirectUri}`
);

3. 新增跨标签页存储事件监听兜底

同域下localStorage变更会向所有同域标签页触发storage事件,通过该机制可快速感知其他标签页的登出动作:

/**
 * 绑定跨标签页存储变更监听
 */
bindStorageSyncListener(): void {
  this.storageListener = (e: StorageEvent) => {
    // 监听到凭证被清空时直接触发本地登出
    if (['access_token', 'id_token', 'sessionState'].includes(e.key || '') && !e.newValue) {
      this.authService.logoutLocal();
    }
  };
  window.addEventListener('storage', this.storageListener);
}

4. 完善本地登出逻辑

本地登出方法需按顺序执行以下操作,避免触发WSO2 id_token解析错误:

  1. 清理定时器、解绑所有事件监听
  2. 清空localStorage/sessionStorage中存储的所有OIDC凭证(client_id、sessionState、access_token、id_token、用户信息缓存)
  3. 跳转至应用登录页,不要携带失效凭证请求WSO2认证端点

注意:WSO2 API Manager 3.2.0对session_state格式校验严格,登录成功后需完整存储OP返回的原始session_state值,不得做截断、转义处理,否则Check Session接口会持续返回错误状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 12:15:39