☰
主系统登录后,子系统怎么实现自动登录?
2026/10/8 6:51:57 网站建设 项目流程

核心回答

跨域没法共享 Cookie,就靠中央认证中心:子系统没登录就跳过去,认证中心确认已登录后再跳回来,子系统建立自己的登录态。

这句话先说到这里就够了。


1. 为什么 Cookie 共享解决不了所有 SSO?

假设:

主系统: https://www.example.com 订单系统: https://order.example.com 数据看板: https://dashboard.example.com

它们属于同一个父域名:

example.com ├── www.example.com ├── order.example.com └── dashboard.example.com

这种情况下,可以考虑:

Set-Cookie: token=xxx; Domain=.example.com

浏览器访问:

order.example.com

时,就可能自动携带:

token=xxx

所以:

同一父域名下,可以通过Cookie Domain共享登录态。

但如果变成:

www.example.com order.example.net dashboard.example.org

就完全不同了。因为:

example.com example.net example.org

之间不能通过 Cookie 的Domain属性互相共享 Cookie。

所以:

Cookie Domain=.example.com

不可能让:

example.net example.org

也收到这个 Cookie。


2. 跨一级域名怎么办?

这时候就不能再想着:

主系统 Cookie ↓ 直接共享 ↓ 子系统

而应该变成:

┌──────────────────┐ │ 中央认证中心 │ │ Auth Server │ └────────┬─────────┘ │ 保存全局登录态 │ ┌──────────────┼──────────────┐ ↓ ↓ ↓ 主系统 订单系统 数据看板 example.com example.net example.org

核心思想非常简单:

不是让不同域名共享 Cookie,而是让不同系统共享同一个认证中心。


3. 最经典的 SSO 流程

例如用户第一次访问:

https://order.example.net

订单系统发现:

当前没有自己的登录态

于是:

订单系统 ↓ 跳转认证中心 ↓ 认证中心检查自己的登录态

假设认证中心发现:

用户已经登录

那么它就不需要用户重新输入账号密码。然后给订单系统一个一次性的认证结果。

以经典 CAS 为例,这个结果就是:

ticket

完整过程:

用户 │ │ 访问订单系统 ▼ 订单系统 │ │ 没有本地 Session ▼ 认证中心 │ │ 检查中央 Session │ │ 已登录 ▼ 生成一次性 Ticket │ │ 重定向回订单系统 ▼ 订单系统后端 │ │ 用 Ticket 服务端请求认证中心 ▼ 认证中心 │ │ 校验 Ticket │ │ 返回用户身份 ▼ 订单系统 │ │ 创建自己的 Session ▼ 用户登录成功

这里有一个特别重要的点:

Ticket 不是最终的登录 Token

不要简单理解成:

认证中心 ↓ 把用户 Token 放 URL ↓ 订单系统直接使用

经典 CAS 更像:

认证中心 ↓ 给一个一次性 Ticket ↓ 订单系统后端 ↓ 拿 Ticket 找认证中心兑换用户身份 ↓ 创建自己的 Session

所以 Ticket 更接近:

“这次认证已经成功了,你拿着这个凭证来找认证中心确认。”

而不是:

“这是用户以后一直使用的登录 Token。”

现代 Web 更常见的是 OAuth 2.0 + OIDC

子系统 ↓ 跳转认证中心 ↓ 认证中心发现用户已登录 ↓ 返回 Authorization Code ↓ 子系统后端拿 Code 换 Token ↓ OIDC 返回 ID Token / 用户身份 ↓ 子系统建立自己的登录态

这里的核心变化是:

CAS: Ticket → 换用户信息 OIDC: Authorization Code → 换 ID Token + Access Token

认证中心到底怎么知道回哪个子系统?

子系统发起登录时,会带上自己的身份和回调地址:

订单系统 ↓ 认证中心 │ ├── client_id=order └── redirect_uri=https://order.example.com/callback

client_id告诉认证中心:

“我是哪个子系统。”

redirect_uri告诉认证中心:

“登录成功后回哪里。”

认证中心通常会提前登记:

order → https://order.example.com/callback dashboard → https://dashboard.example.com/callback

所以认证中心不是自己猜,而是根据client_id找到对应的回调地址,并校验redirect_uri是否匹配。

最终完整流程

用户访问子系统 │ ▼ 子系统发现没登录 │ │ client_id │ redirect_uri ▼ 认证中心 │ ├── 已登录 ─────────────┐ │ │ └── 未登录 │ ↓ │ 用户登录 │ ↓ │ 建立中央 Session │ └───────┬────────┘ ↓ Ticket / Code ↓ 跳回子系统 ↓ 子系统后端校验 ↓ 获取用户身份 ↓ 建立本地 Session ↓ 自动登录

4. 为什么 Ticket 要一次性?

这是这道题很容易继续追问的地方。假设 URL 是:

https://order.example.net/callback?ticket=ST-123456

如果这个 Ticket 永久有效,就存在明显风险。攻击者拿到:

ST-123456

以后可能再次拿它换取用户身份。所以通常要求:

Ticket ↓ 只能使用一次 ↓ 认证中心校验成功 ↓ 立即失效

于是:

第一次使用: Ticket → 校验成功 → 返回用户信息 → Ticket 失效 第二次使用: Ticket → 校验失败

这就是典型的防重放思路。


5. 为什么不直接把 Token 放 URL?

面试官很可能继续问:

“那我直接把 Token 放 URL 里不就行了吗?”

例如:

https://order.example.net?token=eyJ...

这种方案风险比较大。因为 URL 可能出现在:

浏览器历史记录 Referer 访问日志 代理日志 监控系统 截图 用户复制分享的链接

所以:

长期有效 Token ↓ 直接放 URL

通常是不合适的。更合理的是:

URL ↓ 短生命周期、一次性的认证凭证 ↓ 后端服务端校验 ↓ 创建本地登录 Session

6. 前端项目和后端渲染项目有什么区别?

这是一个非常好的追问。假设订单系统根本不是 React/Vue:

Java Spring MVC

而是:

浏览器 ↓ Java 服务 ↓ HTML

它一样可以做 SSO。流程甚至更简单:

浏览器 ↓ 访问 Java 系统 ↓ Java 发现没有 Session ↓ 302 Redirect ↓ 认证中心 ↓ 认证中心发现已经登录 ↓ 302 Redirect ↓ Java 系统 callback ↓ Java 后端拿 ticket ↓ 服务端调用认证中心 ↓ 获取用户身份 ↓ 创建 Java Session ↓ Set-Cookie: JSESSIONID=xxx ↓ 返回页面

所以:

SSO 本质上不是前端路由问题,而是认证系统之间如何建立信任和传递认证结果的问题。

这一点非常重要。


7. 如果是现代 SPA 呢?

如果子系统是:

React Vue Angular

现代项目更常见的方案不一定是 CAS。还可能使用:

OAuth 2.0 OIDC

尤其是:

OIDC = OpenID Connect

可以理解成:

OAuth 2.0 + 用户身份认证 ↓ OIDC

所以面试时最好不要说:

“不同一级域名必须使用 CAS。”

这个说法太绝对。更准确的是:

跨一级域名不能靠 Cookie 共享解决,需要引入中央认证中心;具体可以使用 CAS、OIDC 等标准协议。

这个回答明显更高级。


8. state 到底干什么?

如果继续追问 OIDC / OAuth:

为什么要 state?

不要简单回答:

“state 防 CSRF。”

可以进一步说:

客户端发起认证请求 ↓ 生成随机 state ↓ 保存本地 ↓ 带 state 跳转认证中心 ↓ 认证中心完成认证 ↓ 回调携带 state ↓ 客户端校验两边 state 是否一致

例如:

客户端保存: state = abc123

跳转:

/auth? client_id=xxx &state=abc123

回调:

/callback? code=xxx &state=abc123

然后:

if(callbackState!==savedState){reject();}

核心目的就是:

确认这次回调确实对应当前客户端发起的那次认证请求,避免攻击者伪造认证流程。

所以可以说它用于防 CSRF,但不要把state简化成“一个普通防 CSRF Token”。


9. 用户退出登录怎么办?

这又是 SSO 的另一半:

登录统一,退出也要考虑统一。

假设:

认证中心 │ ├── 主系统 Session ├── 订单系统 Session └── 数据看板 Session

用户在主系统:

点击退出

不能只做:

删除主系统 Cookie

否则可能出现:

主系统:已退出 ❌ 订单系统:还登录着 ✅ 数据看板:还登录着 ✅

这就不是完整的 SSO 退出。


10. 统一登出怎么做?

一种典型架构是:

用户 ↓ 主系统 Logout ↓ 认证中心 ↓ 销毁中央登录态 ↓ 通知各个子系统 ↓ 子系统销毁自己的 Session

例如:

认证中心 │ 全局 Session 删除 │ ┌───────────┼───────────┐ ↓ ↓ ↓ 主系统 订单系统 数据看板 ↓ ↓ ↓ Session Session Session 删除 删除 删除

通知子系统的具体方式可以有很多:

HTTP 回调 消息队列 事件总线 前端重定向退出 标准协议提供的 Logout 机制

不能简单说:

“统一登出就是 MQ 广播。”

因为 MQ 只是一种工程实现方式,不是 SSO 的必然要求。


11. 这道题真正考什么?

其实不是考:

Cookie 怎么设置?

而是考你能不能把这个问题拆开:

登录态在哪里保存? ↓ 不同系统之间能不能共享 Cookie? ↓ 不能共享怎么办? ↓ 有没有中央认证中心? ↓ 认证结果怎么安全传递? ↓ 怎么防重放? ↓ 怎么防 CSRF? ↓ 子系统怎么建立自己的 Session? ↓ 用户退出后怎么同步?

这才是这道题的核心。


12. 面试官继续追问链

这道题可以一路追到很深:

主系统登录后,子系统怎么自动登录? ↓ 为什么不能直接共享 Cookie? ↓ 什么情况下 Cookie 可以共享? ↓ 不同一级域名怎么办? ↓ CAS 是什么? ↓ CAS Ticket 和 Token 有什么区别? ↓ 为什么 Ticket 必须一次性? ↓ 为什么不能直接把 Token 放 URL? ↓ state 是干什么的? ↓ OAuth 2.0 和 OIDC 什么关系? ↓ SPA 和后端渲染项目分别怎么接? ↓ Session 和 Token 怎么选? ↓ 用户退出后怎么实现统一登出? ↓ 多个子系统怎么通知? ↓ 如果认证中心挂了怎么办? ↓ 如果 Ticket 被截获怎么办? ↓ SSO 和权限控制有什么区别?

其中最后两个尤其容易拉开水平。


13. 一个面试时可以直接说的版本

第一段先说这个,不要一上来背 CAS 全流程:

主系统登录后,子系统能不能自动登录,关键看它们能不能共享登录态。同一父域名下可以考虑 Cookie 共享;如果是不同一级域名,就不能直接共享 Cookie,而是让多个系统依赖统一认证中心。子系统发现自己没登录,就跳到认证中心,认证中心确认用户已经登录后返回一次性的认证凭证,子系统后端再向认证中心校验并建立自己的登录态。

如果面试官继续追问 CAS:

经典 CAS 里,这个一次性凭证就是 Ticket。Ticket 通过浏览器带回子系统,但子系统不会直接信任它,而是由后端拿 Ticket 去认证中心校验,成功后创建自己的 Session。Ticket 用一次就失效,这样可以降低重放风险。

如果继续问统一登出:

退出登录也不能只删主系统自己的 Session,而是要先销毁认证中心的全局登录态,再通知各个子系统清理自己的局部 Session,这样才能真正做到单点登录和统一登出。

这三段基本就是这道题的主干答案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询