|
|
很多人在折腾 Xiuno 的时候都会碰到一个需求:多站点共用一个账号体系,也就是单点登录(SSO)。Xiuno 本身比较轻量,没内置完善的 SSO 机制,但并不意味着做不到。这里分享一个更偏工程化、落地可行的思路,尽量不魔改核心,后续也好维护。
先明确边界。SSO 至少解决三件事:统一鉴权(用户在 A 站登录,B 站自动识别)、统一状态(登出同步)、统一资料(头像、昵称等以谁为准)。另外还要考虑 CSRF、重放、跨域 Cookie 等现实问题。很多人第一反应是“共享数据库用户表”,看似简单,其实坑很多:密码哈希策略不同、会话表结构不一致、事务隔离与缓存同步都难控。我的建议是“独立认证中心 + 标准协议(或简单票据)”,业务站点只做“信任票据”的校验和本地会话落地。
最轻量的做法是基于“授权服务器 + 回跳”的票据流。搭一个 auth 子域(如 auth.example.com),它管理用户登录页、注册、找回密码和令牌签发。各个 Xiuno 站点是 Relying Party(RP)。流程是:未登录用户访问论坛 A,被 302 重定向到 auth,登录成功后,auth 生成一次性授权码(短期有效、单次使用),通过回跳地址带回 A;A 用后端后道请求把授权码换取用户信息与会话令牌(含签名),验证通过后在本地建立登录态(Xiuno 的 uid、cookie、session)。这样既避免跨域写 Cookie,又能把安全控在后端。
签名与令牌建议用 JWT,但别直接把 JWT 暴露在前端长期存放。我的实践是:授权码换取两个东西——短期 JWT(比如 5 分钟,只承载用户身份、签发时间、会话 ID),以及一个后端会话票据(存数据库或 Redis),再由站点自己生成 httponly、secure 的站点级 Cookie,实际浏览器只持有站点 Cookie。这样就算 JWT 泄露窗口期也很短,主要控制权仍在服务端。
登出同步是大家常忽略的点。最省事的是“被动同步”:用户在任一站点点击退出,同时后端通知 auth 注销该全局会话 ID;其余站点下次校验或心跳时发现全局会话失效,自动本地登出。若想“立即生效”,可以做一个简易的 back-channel 通知:各站点在 auth 注册回调地址,auth 在注销时向这些回调发 POST,携带会话 ID 和签名,各站本地清理会话。记得做幂等与重试队列。
用户资料的主从问题建议“单一信源 + 本地缓存”。把昵称、头像、邮箱等以 auth 为准,站点只缓存快照。每次换码登录时刷新一遍资料;日常可通过 ETag/版本号减少拉取次数。若站点允许用户改昵称,必须回写 auth 并拿到新版本号,再广播给其他站点(可用消息队列或延迟任务)。强一致不必强求,最终一致即可。
安全细节别省:所有通信都走 HTTPS;授权码设置极短有效期(30-120 秒)且一次性;令牌与回调参数都要绑定原始请求的 state 和 nonce,防止 CSRF 与重放;回跳地址做白名单精确匹配;签名密钥分环境、定期轮换;跨域场景避免第三方 Cookie 依赖,尽量后端换码落地会话。
Xiuno 接入层面,尽量通过插件化切入:拦截登录、退出、检测登录态的几个关键钩子,实现“未登录即跳转 auth;回跳路由处理授权码;本地发起会话;退出时调用 auth 注销”。数据库层面只需在用户表加一个外部 id 映射(如 auth_uid),首次登录时若不存在则“懒创建”本地账号,避免历史数据迁移。
最后给个取舍建议:团队人手够、站点多且还有移动端,直接上成熟协议(OIDC/OAuth2)与现成认证服务(Keycloak、Authing 等);如果是两三个自家站点,追求轻量可控,上面“一次性授权码 + 后端换票 + 本地会话”的自研方案足够稳。别贪图“共享 Cookie 跨子域”这种看似省事的方法,安全与兼容性问题长远看成本更高。 |
|