vue跨系统认证防旧处理:解决假登录、快速切号、兼顾路由守卫性能

参考文章:

https://blog.youkuaiyun.com/qq_45780736/article/details/153470855?spm=1001.2014.3001.5506

以下是 A、B 系统跨子域单点登录(SSO)状态同步的完整实现方案,以清晰的文字流程描述,适用于前端团队协作或文档编写。


🎯 目标

实现:
当用户在 A 系统退出登录 后,跳转到 B 系统 时,B 系统能自动感知会话已失效,并触发登录态检查,避免“假登录”状态。

✅ 前提:A 和 B 同主域,如 a.company.comb.company.com


🧩 核心机制

采用 “时间线矛盾检测 + 用户切换检测”双保险机制

  1. loginTime:记录本次会话的登录时间(由各系统本地维护)
  2. logoutTime:记录全局登出时间(通过跨子域 Cookie 共享)
  3. userId:用于检测用户是否切换账号

B 系统在路由守卫中判断:

  • 是否从外部跳转?
  • 若是,则检查:
    • 用户 ID 是否变化?
    • 登出时间是否晚于登录时间?

任一为真 → 强制调用 checkLogin 接口验证真实登录态。


🔧 完整实现流程

一、A 系统:登录逻辑

  1. 用户登录成功后,执行以下操作:
    • 记录本次登录时间到 localStorage(供 B 系统参考):
      localStorage.setItem('sso-login-time', Date.now());
      localStorage.setItem('sso-user-id', userId);
    • (可选)将 loginTime 存入 Cookie(若 B 无法读 localStorage):
      document.cookie = `sso-login-time=${Date.now()}; domain=.company.com; path=/; Secure; SameSite=None`;

二、A 系统:登出逻辑

  1. 用户点击“退出”:
    • 第一步:先写入“全局登出时间”到跨子域 Cookie:

      const logoutTime = Date.now();
      document.cookie = `sso-logout-timestamp=${logoutTime}; domain=.company.com; path=/; Secure; SameSite=None`;

      ✅ 关键:必须在清除其他 Cookie 之前 写入!

    • 第二步:调用后端 /api/logout 接口,清除服务端会话(Session)。

    • 第三步:清除 A 系统自身的业务 Cookie(如 token、临时数据),但不删除 sso-logout-timestamp

    • 第四步:跳转到目标系统(如 B)或登录页:

      window.location.href = 'https://b.company.com/home?from=a-system&userId=123&t=' + Date.now();

三、B 系统:路由守卫逻辑

在页面加载或路由跳转前执行以下判断:

1. 判断是否从外部系统跳转
  • 检查 URL 参数 from
    • 若 from 存在且不为 b-system,则标记为 外部跳转
2. 获取关键时间与用户信息
  • 本地登录时间 localLoginTime
    • 优先从 localStorage.getItem('sso-login-time') 读取。
    • 若无,可尝试从 Cookie 读取。
  • 全局登出时间 globalLogoutTime
    • 从 Cookie 读取:getCookie('sso-logout-timestamp')
  • 本地用户 ID localUserId
    • 从 localStorage 或缓存中获取。
  • 来源用户 ID fromUserId
    • 从 URL 参数 userId 获取。
3. 判定是否需要强制检查登录态

满足以下任一条件,即触发 forceCheckLogin()

条件说明
isExternal从外部跳转,保守策略,需验证
fromUserId && localUserId && fromUserId !== localUserId用户已切换账号
globalLogoutTime && localLoginTime && +globalLogoutTime > +localLoginTime会话已注销(登出晚于登录)
4. 执行动作
  • 若需检查 → 调用 /api/user/info 接口验证真实登录态。
  • 若无需检查 → 使用本地缓存的 userInfo

📦 数据存储说明

数据存储位置作用域是否可清除
sso-login-timelocalStorage 或 Cookie各系统独立可清除(登录时覆盖)
sso-logout-timestampCookiedomain=.company.com跨子域共享❌ 不可清除(登出时写入后保留)
sso-user-idlocalStorage本地维护可清除

⚠️ 注意:sso-logout-timestamp 的 Cookie 不能被清除,否则 B 无法感知登出事件。


🧪 示例场景

T1: 用户在 a.company.com 登录 → 记录 loginTime = 1729000000000
T2: 用户在 A 退出:
    - 写入 cookie: sso-logout-timestamp = 1729000500000
    - 跳转 https://b.company.com/home?from=a-system&userId=1001
T3: B 系统加载:
    - 检测到 from=a-system → 外部跳转
    - 读取:
        - localLoginTime = 1729000000000
        - globalLogoutTime = 1729000500000
    - 判断:1729000500000 > 1729000000000 → 成立
    - 触发 forceCheckLogin()
T4: /api/user/info 返回 401 或无用户 → 跳转登录页

✅ 优势总结

  • 前端可控:无需后端广播登出事件
  • 无需 iframe:规避安全策略限制
  • 可靠:基于时间线矛盾,逻辑严谨
  • 兼容性好:支持主流浏览器
  • 可扩展:可加入 BroadcastChannel 实现同域标签页同步

📝 注意事项

  1. 时间同步:确保前后端时间误差在可接受范围内(一般 ±1 分钟内无问题)。
  2. Cookie 配置domain=.company.comSecureSameSite=None(如需跨站)。
  3. 防缓存:跳转时加 t=时间戳 参数,避免浏览器缓存页面。
  4. 清理策略sso-logout-timestamp 可设置较短有效期(如 30 分钟),避免长期残留。

🏁 结语

该方案通过 “登出时间 > 登录时间” 的时间线矛盾检测,实现了跨系统登录态的最终一致性,有效解决了“A 退出、B 仍显示登录”的常见 SSO 问题,适合在无统一认证中心(UMS)或 iframe 受限的场景下使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值