Blog

从一个 Vue 3 集成页看 SSO、权限校验与第三方系统跳转设计

拆解一个轻量级 Vue 3 集成页如何串联统一登录、权限校验、第三方用户映射和安全跳转。

  • Vue
  • SSO
  • 前端工程
  • 身份认证
  • 系统集成

在一些企业系统中,前端页面并不一定承载完整业务功能,而是承担“集成桥”的角色:接收用户入口、完成统一身份认证、校验业务权限,然后把用户安全地送到目标系统。

本文结合一个 Vue 3 项目的技术结构,梳理这类集成页的常见设计方式、实现路径和需要注意的安全边界。

相关阅读 SSO 单点登录入门:从概念到前端回调流程 先理解 code、回调地址、token、会话和权限校验,再看本文的 Vue 集成页设计。

项目定位

这个前端应用是一个轻量级单页应用,主要目标不是构建完整后台,而是串联几个外部系统:

  • 统一登录系统
  • 用户订阅或权限校验系统
  • 第三方目标服务
  • 本地状态与跳转控制

用户实际看到的界面很少,主要是“登录中”“身份校验中”“安全退出中”等过渡页。真正的复杂度集中在认证流程、接口调用、跳转控制和异常处理上。

技术选型

项目采用比较典型的 Vue 3 前端栈:

类型 技术
前端框架 Vue 3
语言 TypeScript
构建工具 Vite
路由 Vue Router
状态管理 Pinia
UI 组件 Element Plus
HTTP 客户端 Axios
部署方式 Docker + Nginx

这个组合适合快速实现一个稳定、可维护的集成入口。Vite 负责开发和构建,Vue Router 管理登录回调和退出页,Pinia 存储短期用户状态,Axios 封装不同后端服务的调用。

页面结构

应用通常可以拆成三个核心页面:

页面 作用
首页入口 判断是否已有用户信息,没有则跳转统一登录
登录回调页 处理登录 code,换取用户信息并校验权限
退出页 清理本地状态并跳回业务入口

这种设计的好处是职责清晰:

  • 首页只关心“用户是否可以进入目标系统”。
  • 登录回调页只关心“用户身份和权限是否有效”。
  • 退出页只关心“状态清理和返回入口”。

核心流程

flowchart TD
  entry["用户访问入口页"] --> state{"是否已有用户状态?"}
  state -->|已有状态| targetUser["查询或创建目标系统用户"]
  state -->|没有状态| login["跳转统一登录"]
  login --> callback["登录完成后回调前端"]
  callback --> exchange["使用 code 换取用户信息"]
  exchange --> permission{"调用权限或订阅校验接口"}
  permission -->|无权限| error["提示错误并返回业务入口"]
  permission -->|有权限| save["写入临时用户状态"]
  error --> entry
  save --> targetUser
  targetUser --> link["获取目标系统跳转链接"]
  link --> redirect["重定向到目标系统"]

关键实现点

1. 登录入口只做跳转编排

入口页不应该承载太多业务逻辑。它只需要判断当前是否有临时用户状态:

  • 没有状态:拼接统一登录地址并跳转。
  • 有状态:继续调用目标系统相关接口。

这样可以避免入口页变成“大杂烩”,也让登录回调和业务跳转各自独立。

2. 登录回调页负责身份闭环

登录回调页一般会从 URL 中读取一次性 code,然后调用后端接口换取用户信息。

一个更完整的回调流程通常包括:

  1. 检查 code 是否存在。
  2. 使用 code 获取登录用户信息。
  3. 提取用户唯一标识。
  4. 调用权限或订阅系统做二次校验。
  5. 校验成功后写入临时状态。
  6. 跳回入口页继续后续目标系统跳转。

这个页面要特别注意异常处理。比如 code 为空、接口失败、用户未订阅、用户 ID 缺失,都应该给出明确提示,并跳回可控入口。

3. 第三方服务调用最好通过后端中转

有些第三方接口需要签名、密钥或 client secret。如果这些信息放在前端,即使使用环境变量,也会进入最终构建产物,被浏览器用户看到。

更推荐的结构是:

flowchart LR
  browser["浏览器"] --> backend["自有后端"]
  backend --> thirdParty["第三方服务"]

前端只负责调用自有后端,真实密钥、签名算法、第三方 token 获取都放在服务端。这样可以降低密钥泄漏风险,也方便后端统一做审计、限流和错误处理。

4. 区分全局请求与特殊请求

项目中常见的全局 Axios 封装会做这些事情:

  • 注入 Authorization
  • 统一处理业务 code
  • 统一处理 401、403
  • 统一弹出错误提示

但并不是所有接口都适合走同一个拦截器。例如某些外部接口成功码不是 0,或者 Authorization 规则与内部接口不同,就应该创建独立 Axios 实例,避免全局拦截器误伤。

5. 状态管理要明确生命周期

登录集成页中的用户状态往往只是“跳转过程中的临时状态”。如果使用 Pinia 这类前端状态管理,需要明确:

  • 是否需要刷新后仍然保留?
  • 是否需要持久化到 localStorage?
  • 退出时清理哪些 key?
  • 是否可能影响同域下其他应用?

如果只是一次性跳转流程,内存态可能就够了。如果流程中存在刷新、跨页面或长时间等待,就应该考虑更稳妥的服务端 session 或一次性 token。

部署方式

这类项目很适合用多阶段 Docker 构建:

  1. Node 阶段安装依赖并执行生产构建。
  2. Nginx 阶段托管静态资源。
  3. Nginx 配置 history fallback,支持前端路由刷新。
  4. 对外部接口做代理,规避浏览器 CORS 问题。

需要注意的是,代理并不等于安全边界。如果代理只是把浏览器请求原样转发到第三方,前端仍然可能暴露关键参数。真正敏感的签名和凭证仍然应该放到后端。

安全检查清单

上线前建议检查:

  • 前端构建产物中是否包含真实密钥。
  • 是否把 client secret、AK/SK 等敏感信息放进了前端环境变量。
  • 是否存在硬编码生产地址。
  • 是否有过宽的本地存储清理逻辑。
  • 第三方接口是否应该由后端中转。
  • 依赖审计是否存在高危漏洞。
  • 登录失败、权限不足、订阅过期等异常路径是否可控。
  • 跳转 URL 是否可信,是否需要白名单校验。

总结

SSO 集成页看起来只是几个过渡页面,但它连接了身份、权限、第三方系统和用户跳转,属于安全边界比较敏感的位置。

实现这类项目时,前端应该专注于流程编排和用户反馈;涉及密钥、签名、第三方 token、权限判断的核心逻辑,最好下沉到后端。这样既能保持前端代码简洁,也能让系统在生产环境中更安全、更可控。