openid profile offline_access,若管理端 Client 未登记对应 scope,回调会出现
error=invalid_scope。详见下文「客户端集成说明」。
| 说明 | 地址 |
|---|---|
| OAuth 登录页 | /oauth2/login |
| JWKS | /oauth2/jwks |
| OAuth 回调示例路径 | /demo/callback |
| 管理端登录 | /admin/login/ |
| 管理端 UC 登录 | POST /user/login(tenantId=2,见 README) |
| 用户反馈页 | /oauth2/feedback(须带 client_id、email,见下文「用户反馈」) |
本 AS 基于 Spring Authorization Server,对外暴露标准 OAuth 端点;与常见 OIDC 客户端库的默认假设并不完全一致,集成前请先阅读本节。
| 能力 | 本发行版 |
|---|---|
| 授权码 + PKCE | 主路径(桌面 / SPA / 移动公开客户端) |
POST /oauth2/token、GET /oauth2/jwks、POST /oauth2/revoke | OAuth 2.0 标准端点 |
refresh_token | OAuth 2.0 refresh_token grant;管理端创建 Client 时默认启用(access 30 分钟 / refresh 7 天 / 轮换)。不依赖 OIDC 的 offline_access scope |
OIDC(openid、id_token、UserInfo) | 已验收(US-016):GET /.well-known/openid-configuration、GET /oauth2/userinfo;Client 须登记 openid(及所需 profile/email/phone) |
| access_token | JWT(HS256),含 tenant_id、user_code、role_codes 等项目自定义 claim,供 RS @RequireScope / @RequireRole 使用 |
?error=invalid_scope。openid、profile、offline_access。openid:仅在使用 OIDC / 需要 id_token 时按需登记;不是授权码流程的必选项。profile、offline_access:OIDC 常见 scope,均为可选;未登记却请求 → invalid_scope。scope 填 Client 已登记的角色名即可,不必照搬 OIDC 库默认三件套。+),不要用逗号。authorize 的 scope 只能是该 Client 在管理端已登记 scope 的子集。集成前请与OAuth Client 登记人(管理端 → OAuth 客户端)确认下表所列名称后再编码到客户端。
管理端创建 Client 时,「授权 Scope」下拉来自客户端租户(默认 tenantId=1)下已定义的角色名称。authorize 应携带与 RS 业务 API @RequireScope 一致的角色 scope。
| 说明 | 示例 | 备注 |
|---|---|---|
| 客户端租户自定义角色 | purchase-user、vip 等 |
以管理端「角色管理」与 OAuth Client 登记为准,无全局固定列表 |
| 与 RS 验权对齐 | RS 接口标注 @RequireScope("orders:read") 时,Client 须登记且 authorize 携带 orders:read |
业务 scope 字符串由项目约定,同样须预先登记 |
协作建议:Client 登记人导出该 Client 的「授权 Scope」列表 → 客户端开发按列表配置 authorize;不要自行假设 OIDC 默认 scope 已登记。
下列为 OIDC / OAuth 生态常见 scope 名;仅当管理端已为该 Client 勾选/登记时才能在 authorize 中请求。
| Scope | 类型 | 何时携带 | 本发行版说明 |
|---|---|---|---|
openid |
OIDC | 需要 id_token、走 OIDC 身份层时 |
部分支持,按需登记;token 响应可含 id_token |
profile |
OIDC | 需要基本资料类 claim 时 | 可选;UserInfo GET /oauth2/userinfo(Bearer access_token,须含 openid scope) |
email |
OIDC | 需要邮箱 claim 时 | 可按需登记;consent 页无专用中文描述时使用默认文案 |
address、phone |
OIDC | 需要地址/电话 claim 时 | 同上,按需登记 |
offline_access |
OIDC 惯例 | OIDC 客户端库要求显式申请 refresh 时 | 非必须:本 AS 默认已通过 OAuth 2.0 refresh_token grant 发 refresh,不依赖此 scope |
| 场景 | authorize scope 示例 | 管理端 Client 须登记 |
|---|---|---|
| 桌面/业务客户端(推荐) | {角色名} 或 {角色名} orders:read |
与示例中每一项一致 |
业务 + 需要 id_token |
openid {角色名} |
openid + 对应角色/业务 scope |
| OIDC 客户端库默认三件套 | openid profile offline_access |
三项全部登记;否则 invalid_scope |
| 仅需 access_token + refresh(本项目默认) | {角色名}(不必带 offline_access) |
角色 scope + Client 默认启用 refresh grant 即可 |
access_token(JWT)除 scope 外还含 role_codes(用户在该租户下的实际角色),RS 上 @RequireRole 看 role_codes,@RequireScope 看 token 中的 scope;两者可能同时存在,集成时请与后端约定。
redirect_uri,勾选需要的「授权 Scope」。scope 与上一步登记完全一致(或为其子集)。/oauth2/authorize?... → 登录(/oauth2/login)→ 按需 consent → 回调带 code。POST /oauth2/token(grant_type=authorization_code + PKCE)换取 access_token(及默认启用的 refresh_token;scope 含 openid 时另有 id_token)。GET /.well-known/openid-configuration 读取 Discovery;GET /oauth2/userinfo 携带 Authorization: Bearer {access_token} 获取身份 Claims。curl -s http://127.0.0.1:8080/.well-known/openid-configuration curl -s http://127.0.0.1:8080/oauth2/userinfo \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Accept: application/json"
UserInfo 要求 access_token 授权 scope 含 openid;profile/email/phone claims 须对应 scope 已登记且 authorize 已携带。
GET /oauth2/authorize
?response_type=code
&client_id={管理端创建的 client_id}
&redirect_uri={须与 Client 登记完全一致,需 URL 编码}
&scope={与 Client 登记的 scope 一致,空格分隔}
&state={随机串}
&code_challenge={S256 挑战码}
&code_challenge_method=S256
发行版不预置演示 Client。请先在管理端 OAuth 客户端 中新建 PKCE 公共客户端,redirect_uri 可填示例:
http://127.0.0.1:8080/demo/callback,再按上文拼接 /oauth2/authorize 链接进行验收。
业务 App 在用户本地已登录后,携带 client_id 与 email 跳转至 AS 内置反馈页,无需在授权服务器再次登录即可提交文字与图片。提交成功后按 OAuth Client 配置的「反馈通知邮箱」异步发信;管理端可只读查阅历史反馈。
GET /oauth2/feedback?client_id={clientId}&email={urlEncodedEmail}&returnUrl={可选}
email 由业务 App 从本地登录态读取并自行 URL 编码(如 encodeURIComponent)。示例(将 {client_id} 换为管理端已创建的 Client ID):
http://127.0.0.1:8080/oauth2/feedback?client_id={client_id}&email=user%40example.com&returnUrl=http%3A%2F%2F127.0.0.1%3A8080%2Fdemo%2Fcallback
/oauth2/login。returnUrl 可选;非空时其 scheme + authority 须与 Client 任一 redirect_uri 一致,否则忽略(不展示返回链接,不阻断提交)。POST /file/upload,将响应中的文件名随 POST /oauth2/feedback 表单提交(字段 imageUrls)。spring.mail.*。未配置邮箱或 SMTP 时反馈仍落库,仅跳过发信。管理端默认菜单.csv,侧栏打开 用户反馈(/client/feedback);API 为 POST /manage/feedback/list、POST /manage/feedback/detail/{id}(只读)。{state=LxR1y4Q7lO1WeAWrunybaA, code_verifier=yCyYq6kiZ9a2-GD-GFZ__VvQN-IiSVEuwEBqqCcRrxc, code_challenge=z0ttY_KgMnsxucHPpsz3LXNp72jijNk7t6PecdifjDU}
curl -X POST http://127.0.0.1:8080/user/login \
-H "Content-Type: application/json" \
-d '{"tenantId":"2","userCode":"admin","password":"123456"}'
sql/03-tenant-seed.sql 后使用 admin / 123456(tenantId=2)admin-ui,见 admin-ui/README.md