Files
nanocode/www/docs/sso-integration-plan.md
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

237 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WWW 门户 SSO 接入方案
## 1. 现状分析
### 1.1 www 项目当前架构
- **纯前端 SPA**,单文件 `index.html`,由 nginx 80 端口静态托管
- **无后端**,所有逻辑(认证、数据增删)均在客户端 JS 完成
- 当前认证方式:
- 硬编码账号 `admin / abcd1234`
- 密码经 SHA-256 哈希后存入 `localStorage`
- 登录态由 `localStorage.auth` 标记
- 已有功能:登录、修改密码、添加链接、删除链接
### 1.2 SSO 中心(usercenter)现状
- FastAPI 服务,运行在 `:9000`
- Cookie 配置:`Domain=129.211.173.87`,`SameSite=Lax`,`HttpOnly=True`
- 提供的 API:
- `GET /` — 登录页(支持 `?redirect=` 参数)
- `POST /api/login` — 登录,种 Cookie
- `POST /api/logout` — 登出,清 Cookie
- `GET /api/userinfo` — 返回 `{"username":"admin"}`(需 Cookie 认证)
- `POST /api/change-password` — 修改密码
- CORS 当前仅允许 `:8888`、`:8889`、`:9000`
### 1.3 关键差异
| 项目 | personal-blog | www |
|------|--------------|-----|
| 后端 | FastAPI (`:8889`) | **无后端** |
| 认证方式 | Bearer Token + SSO Cookie 双模式 | 纯 localStorage |
| 接入难度 | 中(需改后端认证逻辑) | 低(仅改前端 JS) |
## 2. 接入方案
### 2.1 核心思路
www 项目没有后端,无法做服务端 Cookie 验签。采用 **前端 API 探测** 方案:
- 页面加载时,JS 跨域调用 SSO 中心 `/api/userinfo`(携带 Cookie)
- 返回 200 → 已登录 → 展示管理功能
- 返回 401 → 未登录 → 展示 SSO 登录按钮
- 登录按钮跳转 SSO 中心,登录后 redirect 回门户
### 2.2 认证流程
```
用户访问 http://129.211.173.87/ (门户首页)
│
▼
JS 调用 SSO /api/userinfo(credentials: 'include')
│
┌────┴────┐
│ │
200 OK 401
│ │
▼ ▼
展示 展示
管理UI 「SSO 登录」按钮
│
▼ 点击
跳转 http://129.211.173.87:9000/?redirect=http://129.211.173.87/
│
▼ SSO 登录成功
浏览器种 Cookie → redirect 回门户
│
▼
页面重新加载 → JS 再调 /api/userinfo → 200 → 展示管理UI
```
### 2.3 跨域 Cookie 可行性分析
| 条件 | 值 | 结论 |
|------|---|------|
| SSO Cookie Domain | `129.211.173.87` | ✅ www (`:80`) 同 IP,浏览器会带 Cookie |
| SameSite | `Lax` | ✅ 顶级导航跳转(redirect)带 Cookie;跨域 fetch 需 `credentials: 'include'` |
| CORS `allow_credentials` | `True` | ✅ SSO 中心已开启 |
| CORS `allow_origins` | 需追加 `http://129.211.173.87` | ⚠️ **需修改** |
> **注意**:`SameSite=Lax` 下,跨域 `fetch` + `credentials: 'include'` 在部分浏览器版本中行为不一致。但当前场景中,用户从 SSO 中心 redirect 回门户时是**顶级导航**,Cookie 一定会带上。fetch 探测仅用于页面加载后的状态检查,即使偶尔探测失败,刷新页面即可恢复。
## 3. 具体改动
### 3.1 SSO 中心(usercenter)— 1 处改动
**文件**:`/home/ubuntu/nanocode/usercenter/app.py`
```python
# CORS allow_origins 新增一行
allow_origins=[
"http://129.211.173.87:8888",
"http://129.211.173.87:8889",
"http://129.211.173.87:9000",
"http://129.211.173.87", # ← 新增:www 门户(80 端口)
],
```
### 3.2 www 门户 — 1 个文件改动
**文件**:`/home/ubuntu/nanocode/www/index.html`
#### 改动清单
| # | 改动 | 说明 |
|---|------|------|
| 1 | 删除 `hashPass` / `checkPass` / `genId` 等本地认证函数 | 不再需要 |
| 2 | 删除 `localStorage` 中 `auth` 相关的读写 | 不再需要 |
| 3 | `isLoggedIn()` 改为基于 SSO 状态变量 | 异步检测,非同步读 localStorage |
| 4 | 新增 `checkSSOStatus()` | 调用 `http://129.211.173.87:9000/api/userinfo`,`credentials: 'include'` |
| 5 | 页面加载时调用 `checkSSOStatus()` | 替代原 `updateNavbar()` 的同步逻辑 |
| 6 | 登录按钮改为跳转 SSO | `window.location.href = 'http://129.211.173.87:9000/?redirect=...'` |
| 7 | 删除「修改密码」入口 | 密码管理统一到 SSO 中心 |
| 8 | 退出改为调用 SSO `/api/logout` | `fetch('.../api/logout', {method:'POST', credentials:'include'})` |
| 9 | 删除登录弹窗 HTML | 不再需要本地登录表单 |
| 10 | 删除修改密码弹窗 HTML | 不再需要 |
#### 核心代码示意
```javascript
// SSO 配置
const SSO_BASE = 'http://129.211.173.87:9000';
let ssoUser = null; // 当前 SSO 登录用户名
// 检测 SSO 登录状态
async function checkSSOStatus() {
try {
const res = await fetch(`${SSO_BASE}/api/userinfo`, {credentials: 'include'});
if (res.ok) {
const data = await res.json();
ssoUser = data.username;
} else {
ssoUser = null;
}
} catch {
ssoUser = null;
}
updateNavbar();
}
// SSO 登录(跳转)
function ssoLogin() {
const redirect = window.location.origin + window.location.pathname;
window.location.href = `${SSO_BASE}/?redirect=${encodeURIComponent(redirect)}`;
}
// SSO 登出
async function ssoLogout() {
await fetch(`${SSO_BASE}/api/logout`, {method: 'POST', credentials: 'include'});
ssoUser = null;
updateNavbar();
}
// 是否已登录(SSO)
function isLoggedIn() {
return ssoUser !== null;
}
// 页面加载
checkSSOStatus();
renderCards();
```
#### 导航栏 UI 变化
**未登录时**:
- 按钮:「SSO 统一登录」(跳转 SSO 中心)
**已登录时**:
- 显示用户名
- 按钮:「添加链接」「退出」
- 移除「修改密码」(统一在 SSO 用户中心管理)
## 4. 实施步骤
### Step 1:修改 SSO 中心 CORS
```bash
# 编辑 /home/ubuntu/nanocode/usercenter/app.py
# allow_origins 增加 "http://129.211.173.87"
# 重启 usercenter 服务
sudo systemctl restart usercenter
```
### Step 2:修改 www 门户 index.html
```
1. 删除:本地认证相关 JS 函数(hashPass、checkPass、genId、doLogin、doChangePass)
2. 删除:localStorage auth 读写函数(setAuth、clearAuth、getAuth)
3. 删除:登录弹窗 HTML(loginModal)
4. 删除:修改密码弹窗 HTML(passModal)
5. 新增:SSO 状态检测函数 checkSSOStatus()
6. 新增:ssoLogin()、ssoLogout() 函数
7. 修改:isLoggedIn() → 基于 ssoUser 变量
8. 修改:updateNavbar() → 未登录显示「SSO 统一登录」,已登录显示用户名 + 退出
9. 修改:页面初始化 → checkSSOStatus() 替代同步 updateNavbar()
```
### Step 3:验证测试
```bash
# 1. 验证 SSO CORS 配置
curl -s -H "Origin: http://129.211.173.87" \
-H "Cookie: access_token=<valid_token>" \
http://129.211.173.87:9000/api/userinfo
# 2. 浏览器测试
# - 访问 http://129.211.173.87/ → 应显示未登录状态
# - 点击「SSO 统一登录」→ 跳转到 :9000 登录页
# - 输入 admin / abcd1234 → 登录成功 redirect 回门户
# - 门户应显示已登录状态,可添加/删除链接
# - 点击「退出」→ 回到未登录状态
```
### Step 4:清理遗留
```bash
# 清除浏览器 localStorage 中旧的 auth 数据
# (无需手动处理,新版代码不再读取旧 auth key,用户清除浏览器缓存即可)
```
## 5. 不改动的部分
- **链接数据**(`localStorage.links`)— 保持不变,与认证无关
- **卡片渲染/3D 倾斜** — 保持不变
- **nginx 配置** — 保持不变
- **SSO 中心核心逻辑** — 仅改 CORS,不动登录/验签/密码逻辑
- **personal-blog 项目** — 无需改动
## 6. 风险与注意事项
| 风险 | 应对 |
|------|------|
| 跨域 fetch 携带 Cookie 在部分浏览器可能失败 | 顶级导航(SSO redirect 回来)后页面刷新自动带 Cookie,fetch 仅作辅助检测 |
| SSO 中心宕机导致门户无法判断登录态 | `checkSSOStatus()` 捕获异常后按未登录处理,不影响门户浏览;管理功能暂不可用 |
| `localStorage.links` 数据无服务端保护 | 原本就是纯前端存储,SSO 接入不改变此现状;后续可考虑升级为后端存储 |