site logo

Marico's space

如何实现 Ace Data Cloud 登录(使用 OAuth 2.0 和 PKCE)

前端技术 2026-08-06 14:49:29 5

最近在给项目接 Ace Data Cloud 的登录功能,官方文档写得很散,自己踩了几个坑才跑通。这篇把 OAuth 2.0 配合 PKCE 的完整流程梳理一遍,包括注册应用、生成授权链接、换取令牌、调 API,都覆盖到。

能做什么

如果你需要代表用户访问 Ace Data Cloud 的资源,让用户手动复制 API Key 是个很糟糕的体验。更合理的做法是用 OAuth 2.0 授权码流程配合 PKCE:用户点登录、授权你请求的权限范围,你的应用拿到一个 access token,只能操作用户授权的那些资源。

这个集成方案适合第三方应用、Agent、MCP 客户端和自动化工作流。

认证基础 URL:

https://auth.acedata.cloud

核心端点列表:

用途 端点
发现文档 GET /.well-known/oauth-authorization-server
浏览器授权 GET https://auth.acedata.cloud/oauth2/authorize
令牌交换或刷新 POST https://auth.acedata.cloud/oauth2/token
撤销令牌 POST https://auth.acedata.cloud/oauth2/revoke
用户信息 GET https://auth.acedata.cloud/api/v1/users/me
OAuth 应用管理 https://auth.acedata.cloud/user/oauth-apps

用 curl 拉取发现文档:

curl https://auth.acedata.cloud/.well-known/oauth-authorization-server

返回的 capabilities 包括:

  • response_type=code
  • grant_types=authorization_code, refresh_token
  • PKCE 支持 S256plain 两种 challenge 方法
  • 客户端认证支持 client_secret_post(机密客户端)和 none(公开 PKCE 客户端)

按最小权限选 Scope

Scope 是 OAuth 比手动复制 API Key 更安全的核心原因——用户能看到你申请了哪些权限,令牌也只限于这些权限范围内操作。

身份相关的 scope:

  • openid:返回用户的唯一 id
  • profile:返回 usernamenicknameavataris_verifieddate_joined 等字段
  • email:返回 email
  • phone:返回 phoneregion

平台资源相关的 scope:

  • applications:readapplications:write
  • credentials:readcredentials:write
  • usage:read
  • orders:readorders:write

还有一些聚合 scope,用起来更省事:

  • platform:read 等价于 applications:read credentials:read usage:read orders:read
  • platform:write 等价于 applications:write credentials:write orders:write
  • platform 包含读写两组

简单登录请求 openid profile 就够。如果是要在 IDE 或 MCP 客户端里配置凭证,请求 openid profile credentials:read credentials:write。只有需要 refresh token 时才加 offline_access

注册 OAuth 应用

到管理页面创建应用:

https://auth.acedata.cloud/user/oauth-apps

注册时选客户端类型:

  • Confidential(机密客户端):后端服务,可以安全存储 client_secret
  • Public(公开客户端):前端、桌面端、CLI、移动端等无法安全存储密钥的场景,必须用 PKCE

还要配置 Redirect URI,必须和你后续发请求时传的 redirect_uri 完全一致。保存后会拿到 client_id。机密客户端还会显示一次 client_secret,看完就消失,立刻记下来。

跳转到授权页面

浏览器重定向到这个地址:

https://auth.acedata.cloud/oauth2/authorize

一个典型的授权 URL 长这样:

https://auth.acedata.cloud/oauth2/authorize ?response_type=code &client_id=<your client_id> &redirect_uri=<your registered callback address> &scope=openid%20profile%20credentials:read &state=<random CSRF protection string> &code_challenge=<PKCE challenge value> &code_challenge_method=S256

state 参数一定要验证,这是你的 CSRF 保护。

PKCE 部分:先生成随机的 code_verifier,然后计算:

code_challenge = BASE64URL(SHA256(code_verifier))

code_challenge 放进授权 URL,把 code_verifier 留着,等下换令牌要用。用户授权后,浏览器会跳回:

<redirect_uri>?code=<authorization code>&state=<state returned as is>

如果用户拒绝,返回 error=access_denied 和一段 error_description

授权码有效期只有 10 分钟,而且只能用一次,拿到就赶紧换令牌。

换令牌

机密客户端用 client_secret 换:

curl -X POST https://auth.acedata.cloud/oauth2/token \ -d grant_type=authorization_code \ -d code=<code obtained in the previous step> \ -d client_id=<your client_id> \ -d client_secret=<your client_secret> \ -d redirect_uri=<callback address that exactly matches Step 2>

公开 PKCE 客户端用 code_verifier 换:

curl -X POST https://auth.acedata.cloud/oauth2/token \ -d grant_type=authorization_code \ -d code=<code> \ -d client_id=<your client_id> \ -d code_verifier=<code_verifier generated earlier> \ -d redirect_uri=<callback address>

成功返回的格式:

{ "access_token": "<JWT>", "token_type": "Bearer", "expires_in": 1296000, "scope": "openid profile credentials:read", "refresh_token": "<JWT, only when offline_access>"
}

access token 是 JWT(JSON Web Token),带 scope 声明,有效期 15 天。refresh token 只有请求了 offline_access 才会返回,有效期 30 天。

用 access token 调 API

读用户信息,把 token 放在 Authorization: Bearer 请求头里:

curl https://auth.acedata.cloud/api/v1/users/me \ -H "Authorization: Bearer <access_token>"

返回哪些字段取决于用户授权了哪些 identity scope。

调平台资源 API 访问 api.acedata.cloud,同样带 bearer token。比如用户授权了 credentials:read

curl https://api.acedata.cloud/api/v1/credentials/ \ -H "Authorization: Bearer <access_token>"

平台后端会校验 JWT 里的 scope 范围。如果 token 想访问未授权的资源,API 返回 403

刷新和撤销令牌

如果请求了 offline_access,access token 过期后可以刷新:

curl -X POST https://auth.acedata.cloud/oauth2/token \ -d grant_type=refresh_token \ -d refresh_token=<your refresh_token>

注意 refresh token 是滚动更新的,每次刷新后会给你一个新的,旧的就失效了,记得存最新的那个。

要撤销任意令牌:

curl -X POST https://auth.acedata.cloud/oauth2/revoke \ -d token=<access_token or refresh_token>

错误处理

OAuth 错误统一格式:

{ "error": "<code>", "error_description": "<human-readable explanation>"
}

常见错误码:invalid_requestinvalid_clientinvalid_grantaccess_deniedunsupported_grant_type

实际集成中最常踩的是 invalid_grant:授权码过期了(10分钟窗口)、授权码被重复使用了、PKCE 校验失败、或者 redirect_uri 不匹配。

几个有用的限制:每个账户最多创建 20 个 OAuth 应用,授权码 10 分钟有效且只能用一次,access token 有效期 15 天,refresh token 有效期 30 天且每次刷新滚动更新,redirect_uri 必须完全匹配。

接这个流程主要就是为了让用户在登录时有个熟悉的体验,同时保持权限范围可控、可审计。如果你在做 Agent、MCP 客户端或者内部面板,这套方案直接能用。