主题
04 — SSO 接入(门户作 IdP)
第三方应用信任门户签发的身份,实现单点登录。本文为实用端点清单;完整方案、安全与分期见 doc/07-单点登录方案.md。
前提:用户须已在门户 sys_user 开户;Client 已在 sys_sso_client 注册(见 01-接入准备.md)。
1. 协议选型
| 协议 | 门户角色 | Client protocol | 典型用途 |
|---|---|---|---|
| OAuth 2.0 | 授权服务端 | OAUTH2(默认) | 授权码换 opaque access_token,调 userinfo / 开放 API |
| OIDC | 同上 + Discovery / JWKS / id_token | OIDC | 需要标准 OIDC 客户端、JWT id_token(RS256) |
| CAS 3.0 | CAS Server | CAS | 传统 CAS Client;须部署授权功能码 sso.cas |
| SAML 2.0 | IdP | SAML | SP 对接 AD FS 等;配置 entity_id / acs_urls |
access_token 为 Sa-Token opaque(存 Redis),不是 JWT。OIDC 时仅额外的 id_token 为 JWT。
不支持:grant_type=client_credentials(Discovery grant_types_supported 仅为 authorization_code、refresh_token)。
2. OAuth2 / OIDC 端点
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /.well-known/openid-configuration | OIDC Discovery(issuer、authorize/token/userinfo/jwks、scopes 等) |
| GET | /oauth2/jwks | JWKS 公钥(验 id_token) |
| GET | /oauth2/authorize | 授权码入口;须已登录门户会话 |
| POST | /oauth2/doConfirm | 用户同意授权(consent_mode 需要时) |
| POST | /oauth2/token | code 换 token(application/x-www-form-urlencoded) |
| POST | /oauth2/refresh | 刷新 access_token |
| POST | /oauth2/revoke | 回收 token |
| GET | /oauth2/userinfo | 用户信息;Token 须含 profile |
| POST | /oauth2/introspect | Token 自省;含 permissions 时返回权限快照 |
授权码流程(摘要)
- 浏览器访问
GET /oauth2/authorize?response_type=code&client_id=...&redirect_uri=...&scope=...&state=...
(OIDC 建议带nonce;scope 含openid) - 未登录 → 302
{issuer}/auth/login?redirect={相对路径 /oauth2/authorize?...},登录成功后前端须整页跳回该 redirect 以继续发码并回第三方;需确认 →/oauth2/consent.html - 成功 → 302
redirect_uri?code=...&state=...(Location 会对 redirect_uri 的 query 值做 percent-encode,避免值中含#时被浏览器截成 fragment 丢code) - 服务端
POST /oauth2/token:grant_type=authorization_code&code=...&redirect_uri=...&client_id=...&client_secret=...
(或 Basic:Authorization: Basic base64(client_id:client_secret)) redirect_uri须与 authorize 时完全一致(含 query,换票要用同一串);白名单校验忽略 query/fragment,只比对 scheme+host+path(登记https://app.example.com/r/ov即可匹配带参回调)。须同时落在 Client 授权域内。
Scope(开放 API 相关)
| scope | 可访问 |
|---|---|
profile | /oauth2/userinfo |
permissions | introspect 扩展 roleCodes / permissions |
api:read | /api/open/** 只读(当前主要为任务查询) |
api:write | /api/open/** 写(任务创建等;蕴含读) |
openid | OIDC:Token 响应含 JWT id_token |
OAuth2 Token 禁止访问 /api/system/* 等门户业务管理 API。任务中心细节见 03-任务中心-OAuth2.md;设计表见 doc/07 §4.6。
Token 换票 curl 示意
bash
curl -sS -X POST "https://portal.example.com/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://app.example.com/oauth/callback" \
-d "client_id=demo-client" \
-d "client_secret=YOUR_SECRET"3. CAS 端点
| 方法 | 路径 | 说明 |
|---|---|---|
| GET/POST | /cas/login?service={url} | 登录并签发 ST,302 至 service?ticket=ST-... |
| GET/POST | /cas/logout | 销毁门户会话后 302 登录页并带 redirect=/cas/login?service=...(service/url 参数或登录时 Cookie);第三方应传与 login 相同的 service |
| GET | /api/auth/cas-resume | 公开;SPA 在 redirect=/ 时按 Cookie 恢复续跳 |
| GET | /cas/p3/serviceValidate?service=...&ticket=... | 校验 ST,返回 CAS XML(一次性) |
Client 侧登记允许的 service URL(protocol_config.service_urls 与 redirect_uris 均计入白名单;根路径有无尾 / 等价)。未授权功能码时 validate 返回 LICENSE 失败 XML。
管理端编辑 CAS Client 时须同步更新两处;仅改界面「服务地址」而库内旧 service_urls 不一致时,旧版会报「未登记的 service URL」。
4. SAML IdP 端点
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /saml/idp/metadata | IdP 元数据 XML |
| GET/POST | /saml/idp/sso | SSO(携带 SAMLRequest) |
| GET/POST | /saml/idp/slo | 单点登出 |
Client protocol=SAML 时配置 entity_id、acs_urls 等(见创建 Client 请求字段)。默认 EntityID 形态:{issuer}/saml/idp。
5. 与开放 API / 出向的关系
| 能力 | 是否用本 Token |
|---|---|
/api/open/tasks/** | 是(需 api:* scope) |
/api/open/matters/** | 否(HMAC,见 02) |
| 接收组织用户出向推送 | 无 Token;你方暴露 HTTP,见 05 |
管理端配置 Client / 出向:/api/sso/clients、/api/sync/** 仍属门户运维面,第三方不直接调用。
6. 对接检查清单
- Client:
redirect_uris/ 授权域 /scopes/protocol正确;生产 HTTPS。 - OIDC:拉取 Discovery 与 JWKS;校验
id_token的iss/aud/nonce。 - CAS:
serviceURL 与 validate 时一致。 - SAML:交换元数据,ACS 与门户配置一致。
- 需要调任务开放 API:authorize 时申请
api:write(或api:read)。
细节与分期以 doc/07-单点登录方案.md 为准;若与本文冲突,以代码与 Knife4j 为准,并提请更新本目录。
小程序 web-view 与业务域名
终端用户从微信小程序打开贵方 H5 时:门户先在小程序内换一次性票,经门户落地页为 web-view 种与 PC 相同的门户会话 Cookie,再进入贵方入口 URL;之后访问 /oauth2/authorize(或 CAS/SAML)与浏览器 PC 流程相同,第三方无新协议、无新回调字段。会话桥见 doc/54-小程序H5会话桥.md。
打开只有这一条。 不要让门户把长期 Token 拼进 URL;不要在 H5 里放 client_secret。
微信侧(PC 没有、小程序必做):
| 项 | 说明 |
|---|---|
| 业务域名 | 公众平台 → 开发管理 → 业务域名。须逐条加:门户 issuer 主机(落地页 /auth/mp-webview-bridge)+ 每一个 H5 主机。不支持通配符。 |
| 校验文件 | 微信下发 MP_verify_….txt,放到该主机站点根。门户自有 Nginx 已 include default.d 的站点(如 smart.*、nyxg.demo.*)可走仓库 deploy/nginx/default.d/site-verify.conf;不在门户 Nginx 上的业务系统须自己放文件。 |
| 开发 vs 真机 | 开发者工具可勾「不校验合法域名」;体验版 / 正式版不行。 |
门户应用移动地址应配贵方 SSO 入口(例如 /pub/sso/smart/auth?redirect=...),小程序会话桥校验 next 与登记 appUrl 同 origin。
样板:能源 H5(ny-app)
能源后端已按 WeCard / KIM 同构接本门户(ny-java GET /pub/sso/smart/auth)。H5 仍只读能源自己的 access_token(LoginByToken),不改 OAuth 协议。
- 管理端为 H5 SP 登记 OAuth2 回调(可在现有能源 Client 上「添加回调地址」,或新建 Client):
protocol=OAUTH2,redirect_uris含https://nyxg.demo.hechuanghuixin.com/pub/sso/smart/callback,allowedDomains含nyxg.demo.hechuanghuixin.com(不必加 H5 子域),scope 含profile,关闭强制 PKCE。PC 已有的/pub/sso/portal/callback/...不要改。 - 能源进程写入
SMART_SSO_CLIENT_ID/SMART_SSO_CLIENT_SECRET/SMART_SSO_APP_URL=https://nyxg.demo.hechuanghuixin.com(及可选SMART_SSO_INNER_BASE)。H5 独立子域时再配SMART_SSO_ALLOWED_REDIRECT_HOSTS=nyxgapp.demo.hechuanghuixin.com、SMART_SSO_H5_BASE=https://nyxgapp.demo.hechuanghuixin.com(代码默认已是这两项)。 - 门户应用:仅移动;
appUrl=https://nyxg.demo.hechuanghuixin.com/pub/sso/smart/auth?redirect=+encodeURIComponent(https://nyxgapp.demo.hechuanghuixin.com/#/wel/index)
会话桥 origin 是nyxg.demo;落地页才是nyxgapp.demo。种数脚本:smart-home-ui/scripts/seed-energy-patrol-mobile-apps.mjs。 - 用户映射:门户
username= 能源userCode;两边都要有这个人。 - 公众平台业务域名加上
smart.hechuanghuixin.com、nyxg.demo.hechuanghuixin.com(SSO)与nyxgapp.demo.hechuanghuixin.com(H5)。 - 验收:小程序正式用户点应用 → 会话桥 →
nyxg.demo上/pub/sso/smart/auth→ 门户 authorize → 已登录的 ny-app(nyxgapp.demo)。PC 管理端仍走原/pub/sso/portal/callback/...。
换票须 POST /oauth2/token(application/x-www-form-urlencoded),不要学部分旧 IdP 用 GET。userinfo 为 GET /oauth2/userinfo + Authorization: Bearer。能源 H5 为 hash 路由,回跳 redirect 须带 #/wel/index。
细节与环境变量见能源仓 ny-java/README.md「融合门户 SSO」。
7. 下载 Demo
- 精简 OAuth2/OIDC 客户端 Java:/downloads/sso-oauth2-client-java.zip
- 说明:sdk/sso-oauth2-client-java/README.md(不含完整 ssoDemo / CAS / SAML)