6.1 KiB
DeepData × Casdoor SSO 部署运维手册(31.23)
适用范围:DeepData(
com.deepdata)网关单点登录接入自建 Casdoor v2.153.0。 生产实例:31.23(Casdoor:1013,DeepData 网关:8080,前端/入口deepdata.yhdd.apescale.com:1014)。 代码版本:≥4e2ec55(M3:移除 accountOnly,本地登录与 SSO 共存;登录时自动建号,无定时同步)。
1. 架构与登录流
浏览器 → DeepData 网关 /api/user/oauth/login?next=…
→ 302 Casdoor /login/oauth/authorize(state+next 存 HttpOnly cookie,TTL 300s)
→ Casdoor 登录/同意
→ 回调 /api/user/oauth/callback?code&state
→ 网关换 token → JWKS 验 id_token → upsert 本地用户(自动建号/刷组刷角色)
→ 302 next?sso_token=<本地HS256 JWT>(含 role/groups claims)
→ 前端 callback.html 种 token 进入应用
失败时回跳 next?sso_error=<code>(state_mismatch / code_exchange / id_token_verify / internal)。
角色映射:Casdoor 组 deepdata-admin|dev|annotator|viewer(组路径 datamate/<group>)→ 本地 role,由 RoleResolver 按「映射 > 主角色 > defaultRole」解析;组与角色随每次 SSO 登录刷新。
2. Casdoor 侧一次性配置(生产现状)
| 对象 | 值 | 说明 |
|---|---|---|
| 组织 | admin/built-in、admin/datamate |
password_type=bcrypt |
| 组(owner=datamate) | deepdata-admin deepdata-dev deepdata-annotator deepdata-viewer |
与 casbin 规则对齐 |
| 用户(owner=datamate) | dmin(4 组)、viewer1(viewer) |
tag='DeepData' 必须与应用 tags 一致;建议给真实 email |
| 证书 | admin/cert-built-in |
应用引用用裸名 cert-built-in |
| 应用 | admin/DataMate |
clientId 144f4d00553aa7db0aab;tags ["DeepData"];tokenFields ["Groups"];redirectUri=https://deepdata.yhdd.apescale.com:1014/api/user/oauth/callback;expire_in_hours ≥ 1 |
| Casbin | dmin 4 条 / viewer1 1 条 | 角色→组权限 |
踩坑清单(均已踩过,排查先对这里)
expire_in_hours必须 ≥ 1:应用列名是expire_in_hours(double),不是 token_expiration。为 0 时expires_in=0,id_tokenexp=iat,网关验证报JWT expired N milliseconds ago。UPDATE application SET expire_in_hours=1 WHERE owner='admin' AND name='DataMate';- 用户 tag 必须在应用 tags 里:否则 casdoor 登录报
User's tag: is not listed in the application's tags。 /api/login收 JSON body(不是表单):{"type":"login","application":"DataMate","username":"dmin","password":"…","organization":"datamate","autoSignin":true}。/api/grant-consent的application必须全名admin/DataMate(裸名报Invalid application);session cookie 与登录同 host(cookie 域陷阱)。- authorize 无服务端 302:带 session 的 GET 只返回 SPA 页面,重定向由前端
grant-consent后完成——脚本化验证直接调POST /api/grant-consent。
3. DeepData 侧配置
deployment/docker/deepdata/.env(compose 注入,变量名映射见 docker-compose.yml):
DEEPDATA_CASDOOR_ENABLED=true
DEEPDATA_CASDOOR_ISSUER=https://sso.yhdd.apescale.com:1014
DEEPDATA_CASDOOR_AUTHORIZE_URI=http://192.168.31.23:1013/login/oauth/authorize
DEEPDATA_CASDOOR_TOKEN_URI=http://192.168.31.23:1013/api/login/oauth/access_token
DEEPDATA_CASDOOR_JWKS_URI=http://192.168.31.23:1013/.well-known/jwks.json
DEEPDATA_CASDOOR_CLIENT_ID=144f4d00553aa7db0aab
DEEPDATA_CASDOOR_CLIENT_SECRET=***
DEEPDATA_CASDOOR_REDIRECT_URI=https://deepdata.yhdd.apescale.com:1014/api/user/oauth/callback
JWT_SECRET=<不变,本地 JWT 签名密钥>
ISSUER 用公网域名(id_token issuer 断言用);三个 URI 用内网直连(网关→casdoor 同机)。
4. 构建与部署
cd /opt/deepdata/deepdata
make gateway-docker-build frontend-docker-build # 产物 deepdata-{gateway,frontend}:latest
cd deployment/docker/deepdata
docker compose up -d --force-recreate deepdata-gateway deepdata-frontend
注意:跳板机链路构建长任务易断连,长构建用 nohup … > /tmp/gw_build.log 2>&1 & 后台跑再轮询日志。
同步代码到 31.23 只按文件同步、禁用 rsync --delete,同步后 git hash-object 逐文件核对。
5. 验证
GW_BASE=https://deepdata.yhdd.apescale.com:1014 \
CASDOOR_BASE=http://192.168.31.23:1013 \
SSO_CLIENT_ID=144f4d00553aa7db0aab \
LOCAL_ADMIN_PASSWORD=<本地admin密码> \
SSO_TEST_USERS="dmin:<dmin密码>:admin viewer1:<viewer1密码>:viewer" \
bash scripts/casdoor-sso/e2e-check.sh
覆盖:配置公开且无 secret 泄漏 → 本地登录(与 SSO 共存)→ SSO 全链路(authorize→登录→consent→callback→sso_token→/me 角色断言)。
网络注意:公网域名经 222.128.20.101 转发到 31.23:1014,不要用 --resolve 把域名指到 192.168.31.23(该地址本地未监听);E2E 直接访问公网域名即可。
6. 排障
| 现象 | 原因 | 处理 |
|---|---|---|
sso_error=id_token_verify + 网关日志 JWT expired |
应用 expire_in_hours=0 |
见 §2 坑 1 |
sso_error=internal + provision race … reusing existing user 后 NPE |
本地 email 列 NOT NULL UNIQUE,空 email 互撞(代码已修为空 email 合成 username@casdoor.local) |
升级网关镜像;存量行 UPDATE users SET email=… WHERE email=''; |
casdoor 登录 User's tag: is not listed… |
用户 tag 不在应用 tags | UPDATE user SET tag='DeepData' WHERE owner='datamate'; |
grant-consent Invalid application |
application 用了裸名 | 用 admin/DataMate |
| authorize 返回 200 不跳转 | 正常(SPA 行为);若脚本验证用 grant-consent | — |
/sso/casdoor/config enabled:false |
DEEPDATA_CASDOOR_ENABLED 未注入 |
检查 .env + compose 变量名映射 |
/sso/callback.html 403(nginx permission denied) |
文件权限 600,nginx worker 非 root 读不到(构建把 600 烤进镜像) | chmod 644 frontend/public/sso/callback.html 后重建前端镜像 |