OA ⇄ CRM 单点登录(SSO)实现说明

本文档说明在本仓库中基于自研认证体系(未使用 Django 默认认证)实现 OA → CRM 单点登录的整体方案、修改点、接口规范、配置方式、验证方法与安全要点。

### 一、实现目标
- 在 OA 系统成功登录后,点击“进入CRM系统”即可自动登录 CRM,无需再次输入用户名密码。
- 兼容现有自定义会话结构与中间件,不改动既有业务登录逻辑。

### 二、整体架构与流程
1. 用户在 OA 登录(`/login/`)成功,OA 设置自己的会话 `request.session["app"]`。
2. 用户点击 OA 导航中的“进入CRM系统”:访问 OA 的 `/crm/sso/redirect/`。
3. OA 从自己的会话中取出用户名,拼装参数 `username|ts|nonce`,使用共享密钥 `SSO_SHARED_SECRET` 生成签名 `sig`,并重定向到 CRM 的 `/oa/sso/login/`。
4. CRM 校验签名、时间窗口等,通过后在 CRM 端创建与自研体系一致的会话 `request.session["app"]` 并登录,随后跳转到目标页面。

### 三、关键代码位置

1) OA 侧
- 跳转视图:`oa/app/view/account.py` → `crm_sso_redirect`
- URL:`oa/oa/urls.py` 添加 `path('crm/sso/redirect/', account.crm_sso_redirect, name='crm_sso_redirect')`
- 导航入口:`oa/app/templates/layout.html` 导航栏加入“进入CRM系统”按钮,指向 `/crm/sso/redirect/?next=/index/`
- 中间件白名单:`oa/app/middleware/auth.py` 允许匿名访问 `/crm/sso/redirect/`
- 配置:`oa/oa/settings.py` 新增 `CRM_BASE_URL` 和共用的 `SSO_SHARED_SECRET`

2) CRM 侧
- SSO 登录视图:`app/view/account.py` → `oa_sso_login`
- 辅助接口:`sso_status_api`(查看登录态)、`sso_debug`(生成调试链接)
- URL:`CRM/urls.py` 已包含以下路由
  - `path('oa/sso/login/', account.oa_sso_login)`
  - `path('sso/status/', account.sso_status_api)`
  - `path('sso/debug/', account.sso_debug)`
- 中间件白名单:`app/midieware/auth.py` 放行上述 3 个路径
- 配置:`CRM/settings.py` 包含同一份 `SSO_SHARED_SECRET`

### 四、接口与签名规范

1) OA → CRM 重定向
- 目标:`{CRM_BASE_URL}/oa/sso/login/`
- Query 参数:
  - `username`:OA 当前用户在 CRM 中的用户名
  - `ts`:时间戳(秒)
  - `nonce`:随机字符串(防重放)
  - `sig`:签名
  - `next`:登录后跳转页面(可选,默认 `/index/`)

2) 签名规则
- 拼串:`payload = f"{username}|{ts}|{nonce}"`
- `sig = HMAC_SHA256(SSO_SHARED_SECRET, payload)`,以 16 进制字符串输出
- 时间窗口:±120 秒(超时拒绝)
- 校验:CRM 使用相同密钥与规则计算,对比 `sig`,并检查时间窗口

3) CRM 登录逻辑
- 通过签名与时间窗口后,CRM 检索 `models.Admin.objects.filter(username=username).first()`
- 校验用户是否存在/是否被禁用
- 构造 CRM 自定义会话:
  ```python
  request.session["app"] = {
      'id': admin_obj.id,
      'name': admin_obj.name,
      'username': admin_obj.username,
      'role': admin_obj.role,
  }
  request.session.set_expiry(60*60*24*7)
  ```

### 五、配置项

1) 双端共享密钥(必须一致)
- `oa/oa/settings.py`:
  ```python
  SSO_SHARED_SECRET = '123abc!@#'  # 请在生产替换并保密
  ```
- `CRM/settings.py`:
  ```python
  SSO_SHARED_SECRET = '123abc!@#'
  ```

2) 服务地址
- OA 访问地址:`127.0.0.1:8018`
- CRM 访问地址:`127.0.0.1:8009`
- OA 中 CRM 基地址:`oa/oa/settings.py`
  ```python
  CRM_BASE_URL = 'http://127.0.0.1:8009'
  ```

3) Cookie 隔离
- OA:`oa/oa/settings.py` → `SESSION_COOKIE_NAME = 'oa_sessionid'`
- CRM:`CRM/settings.py` → `SESSION_COOKIE_NAME = 'crm_sessionid'`

### 六、白名单与中间件

1) OA 中间件 `oa/app/middleware/auth.py`
```python
if request.path_info in ["/login/", "/image/code/", "/logout/","/register/","/crm/sso/redirect/"]:
    return
```

2) CRM 中间件 `app/midieware/auth.py`
```python
if request.path_info in ["/login/", "/image/code/", "/logout/","/register/","/oa/sso/login/","/sso/status/","/sso/debug/"]:
    return
```

### 七、前端入口

`oa/app/templates/layout.html` 导航栏:
```html
<li><a href="/crm/sso/redirect/?next=/index/" target="_blank">进入CRM系统</a></li>
```

可按需调整 `next` 到 CRM 具体页面,例如 `/customer/list/`。

### 八、验证步骤
1. 启动 OA 于 `127.0.0.1:8018`,CRM 于 `127.0.0.1:8009`。
2. 浏览器登录 OA `/login/`。
3. 点击 OA 顶部“进入CRM系统”。
4. 期望效果:自动跳转并登录 CRM(无需输入密码),到达 `next` 指定页面(默认 `/index/`)。
5. 联调辅助:
   - CRM 查看登录态:`/sso/status/`
   - CRM 生成调试链接:`/sso/debug/?username=<crm用户名>`

### 九、安全要点
- 强制使用 HMAC-SHA256 + 共享密钥校验,避免伪造。
- 采用 `ts + nonce` 防重放,限制时间窗口(±120 秒)。
- 双站点使用不同的 `SESSION_COOKIE_NAME`,避免 Cookie 冲突。
- 生产环境务必更换 `SSO_SHARED_SECRET` 并妥善保密,不要入库或提交到公开仓库。
- 建议为 SSO 接口加上访问频率限制与审计日志。

### 十、常见问题
- “跳转后提示 Invalid signature/expired”:检查两端 `SSO_SHARED_SECRET` 是否一致、机器时间是否同步、链接是否过期。
- “User not found in CRM”:确认 CRM 数据库中存在同名 `Admin.username`。
- “登录成功但显示权限不足/菜单不对”:核对 CRM 里该用户的 `role/status`。

### 十一、后续可选增强
- 增加 SSO 单点登出(SLO):在一端退出同步通知另一端清理会话。
- 增加签名密钥滚动与版本号,便于安全升级。
- 通过后端存储 `nonce` 使用记录,进一步抵御重放攻击。




评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一路生花工作室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值