免登与会话
免登与会话
基座对插件的铁律只有一条:只透传身份,绝不判定应用内权限。应用内"这个人能干什么"完全由插件自己决定。本节讲基座怎么把登录主体安全地交给插件。
谁在哪种形态下拿到身份
| 场景 | 拿身份的方式 |
|---|---|
| 管理入口(基座 qiankun 内) | Bridge 注入,auth.getUserProfile/auth.getSession,本就免登 |
| 前台入口独立直访(同域一方插件) | 内置免登:本地会话优先 → 一次性票据兜底(零对接,见下) |
| 三方 / 跨域 / 独立后端应用 | 后端 consume 换 sid,自建会话 |
身份统一用 sid(sys_ 前缀的人主体)表示,详见统一身份扩展。
一次性票据 ticket
基座 TicketService 签发一次性票据,安全特性:HMAC-SHA256 签名(不可伪造)、绑定 sid + 应用(aud)+ 入口、短时效(默认 60s)、Redis jti 原子核销(一次性,防重放)。同一套票据支撑两条兑换通道:
| 通道 | 端点 | 调用方 | 换得 |
|---|---|---|---|
| 后端 consume | POST /oauth/ticket/consume | 应用后端(服务器间) | { sid, entry, identity },由应用自建会话 |
| 前端 exchange | POST /oauth/ticket/exchange | 同域一方插件前端 | { accessToken, refreshToken, user }(基座主 JWT) |
issue需基座登录态:POST /oauth/ticket/issue { app_id, entry },返回带?ticket=的目标 URL。exchange在noNeedLogin白名单,凭票据本身兑换;校验 aud 绑定(票据只能由签发时绑定的那个应用兑换)。- 三方应用(
type=3)走consume并另带client_secret;exchange一律拒绝type=3(无同源前提)。
边界不变
基座绝不向 type=3 三方应用签发主 JWT;exchange 只是把同域一方插件的免登成本降到零,没有突破"只透传身份、不判应用内权限"的边界。
同域统一会话 atrman:session
生产环境基座、会员中心、各前台插件同域部署,天然共享同一份 localStorage。据此定义跨端会话契约键 atrman:session:
// localStorage["atrman:session"]
{
"accessToken": "Bearer <主 JWT>",
"refreshToken": "Bearer <刷新令牌>",
"user": { "id": 1, "sid": "sys_...", "nickname": "张三", "account_type": 1 },
"expiresAt": 1700000000000
}约束:键名固定、无版本前缀,是"各端用户信息一致"的唯一真源;各 app 自己的 pinia 持久化键端间互不可读,不能当真源;基座/会员中心/am_plugin 各持一份等价的会话工具,改键名或形状须多端同步。
前台免登时序(本地优先 → 票据兜底)
am_plugin 的 bootstrapStandaloneAuth() 在独立前台入口自动执行,开发者零对接:
点应用 → 基座 issue 一次性票 → 拼 ?ticket= 到 entry → 新标签打开 /app/{name}?ticket=
插件 bootstrap:
1) readSession() 命中有效会话 → 直接水合,零网络(生产同域常态)
2) 读不到 → 取 URL ticket → exchange 换主 JWT → writeSession + 水合 → 抹掉地址栏票据
3) 都没有 → 保持未登录,公开页照常浏览
setupSessionSync() 以 storage 监听实现跨标签登录态一致兑换成功后立即 stripTicketFromUrl()(replaceState,不新增历史),防票据残留/被分享/重复兑换。任一端 logOut() 清 atrman:session,经 storage 监听令同域各端一并失效(一致登出)。
未登录怎么引导去登录
插件不自建登录/注册页,统一跳会员中心插件:登录/注册是同页签整页跳走、成功后整页签票带回当前 hash 深链;个人资料是新标签跨应用浏览。由 @/sdk 的会员对接函数封装(见插件 SDK)。
前端 401 与门控
前台公开/会员混合页收到业务形 401(后端 requireMember 返回,见会员态鉴权)时:清会话 → 广播 401 事件 → <RequireLogin> 门控翻牌 →(曾登录时)防抖通知带"重新登录"按钮,不自动整页跳走(公开页自动跳会打断浏览)。
- 页面级门控用
<RequireLogin>:插槽内是已登录内容,未登录就地显示"登录 / 免费注册 / 我已在其他标签登录(刷新)"。 - 动作守门用
requireLogin():未登录跳登录并返回false中止动作。 - front 路由守卫不消费
meta.requiresAuth,一律放行;门控交给组件与动作函数。
本地跨端口
基座/会员中心/插件本地各占一端,localStorage 不互通,"本地优先"落空走票据兜底;只有生产同域才命中本地优先。完整登录闭环需同域 host / 反向代理联调。
