前端oidc-client静默刷新一直提示:Error: Frame window timed out?

基础配置如下:

const base = import.meta.env.VITE_APP_BASE_SSO;
const back_uri = import.meta.env.VITE_APP_BASE_HTTP;

const config = {
  authority: base,
  client_id: 'xxxxxxxxx',
  redirect_uri: back_uri,
  response_type: 'id_token token',
  scope: 'xxxxxxxxxxxx',
  silent_redirect_uri: back_uri,
  automaticSilentRenew: true,
  silentRequestTimeout: 30000, 
  userStore: new WebStorageStateStore({ store: window.localStorage })
};
const userManager = new UserManager(config);

登录是成功的,token过期前60秒会自动静默刷新

userManager.events.addUserLoaded(async (user: User) => {
  account.access_token = user.access_token;
  account.expiresIn = user.expires_at;
  account.token_type = user.token_type;
  let res = await getOwnerUserAPI();
  account.userid = res.userid;
  account.username = res.userName;
  if (isFirstLogin) {
    isFirstLogin = false;
    router.push('/home');
  }

关键是静默刷新的时候addUserLoaded事件执行了,token也更新了,但过了几秒后又执行了addSilentRenewError,提示静默刷新失败 Error: Frame window timed out


// 静默刷新token失败处理
userManager.events.addSilentRenewError(error => {
  console.error('静默刷新失败', error);
  // 可以在这里处理刷新失败后的逻辑,比如跳转到登录页
});

试过延长silentRequestTimeout依旧无效,silentRequestTimeout的时间是30000毫秒基本上也能处理静默刷新的响应了吧

阅读 1.4k
1 个回答

🔍 问题分析

✅ 正常情况

  1. automaticSilentRenew: true 表示 token 过期前会自动触发静默刷新。
  2. 静默刷新使用 <iframe> 请求 silent_redirect_uri,并从中解析 token。
  3. 如果刷新成功,则会触发 addUserLoaded
  4. 如果出错(比如请求超时或 iframe 加载失败),会触发 addSilentRenewError

🚨 异常现象

  • 你观察到:

    • addUserLoaded 被触发(说明确实收到新的 token)。
    • 随后仍然触发 addSilentRenewError,提示:Frame window timed out。

这说明一个问题:token 刷新操作其实成功了,但 oidc-client 的某个内部逻辑仍然以为超时了


✅ 常见原因及解决方案

1. silent_redirect_uri 页面没有正确调用 userManager.signinSilentCallback()

这是最常见的原因:

🔧 检查:

你配置了:

silent_redirect_uri: back_uri

但这个地址必须指向一个页面,该页面在被 iframe 加载时能够调用:

userManager.signinSilentCallback()

👉 解决方案:

  1. 新建一个 silent-renew.html/silent-renew 页面。
  2. 在页面中加入以下代码:
ts复制编辑// silent-renew.ts
import { UserManager } from 'oidc-client';

new UserManager({}).signinSilentCallback();
  1. 并确保这个页面的 URL 是你配置的:
silent_redirect_uri: `${back_uri}/silent-renew.html`

⚠️ 注意:

  • 如果 silent_redirect_uri 指向的是 SPA 的首页(比如你配置的 back_uri 是根目录),当 iframe 加载这个地址时,可能没有自动执行 signinSilentCallback(),就导致了超时。
  • 即便用户信息最终被更新了(如你观察到的那样),内部超时机制已经触发,最终还是会报错。

2. token 实际刷新了两次(可能是状态管理冲突)

你提到 addUserLoaded 成功,然后几秒后报错。这可能是因为:

  • token 第一次刷新成功;
  • 但随后 UserManager 认为状态不一致(比如 store 中还没更新),再尝试刷新一次,导致 iframe 超时。

🔧 解决方案:

在你的 addUserLoaded 回调中加入日志,检查是否重复调用了刷新流程。


3. 浏览器环境限制 iframe 的行为(尤其是 Chrome 的隐私政策)

部分浏览器(尤其是 Chrome 和 Safari)对 第三方 iframe 的 CookieStorage、跳转等行为进行了严格限制,尤其在跨域下。

🔧 解决方案:

确保:

  • silent_redirect_uri 和主站处于同一域名下。
  • 如果使用的是跨域的 SSO 服务,配置正确的 CORS + Cookie 策略。

可以设置 SSO 服务端响应头如下:

http复制编辑Access-Control-Allow-Origin: https://your-frontend-domain.com
Access-Control-Allow-Credentials: true

并设置:

userManager = new UserManager({
  ...
  // 确保这项设置
  checkSessionInterval: 10000, // 可选,定时检查会话
});

✅ 推荐的最终配置示例

ts复制编辑const config = {
  authority: base,
  client_id: 'xxxxxxxxx',
  redirect_uri: `${back_uri}/callback`,
  response_type: 'id_token token',
  scope: 'openid profile email',
  silent_redirect_uri: `${back_uri}/silent-renew.html`, // 注意确保这个页面存在且正确执行 callback
  automaticSilentRenew: true,
  silentRequestTimeout: 10000, // 一般 10 秒就够
  userStore: new WebStorageStateStore({ store: window.localStorage }),
};
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题