237 lines
8.0 KiB
Markdown
237 lines
8.0 KiB
Markdown
# 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 接入不改变此现状;后续可考虑升级为后端存储 |
|