跳到主内容

动态客户端注册

Dynamic Client Registration (DCR) 允许您的软件通过一次 HTTP 请求即可在 Casdoor 中注册 OAuth 客户端,而无需在管理员 UI 中手动创建应用。这在向最终用户分发工具时很有帮助:MCP客户端、CLI或桌面应用可在首次运行或安装时获取客户端凭据。 Casdoor 实施了 RFC 7591。

注册端点​

该端点在 OIDC 发现中公开。请求 /.well-known/openid-configuration:

curl https://your-casdoor.com/.well-known/openid-configuration

使用 registration_endpoint 的值(例如 /api/oauth/register)进行注册:

{
"issuer": "https://your-casdoor.com",
"authorization_endpoint": "https://your-casdoor.com/login/oauth/authorize",
"token_endpoint": "https://your-casdoor.com/api/login/oauth/access_token",
"registration_endpoint": "https://your-casdoor.com/api/oauth/register",
...
}

注册客户端​

使用 JSON 元数据向 /api/oauth/register 发送 POST 请求:

curl -X POST https://your-casdoor.com/api/oauth/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "Claude Desktop",
"redirect_uris": ["http://localhost:3000/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "none",
"application_type": "native"
}'

响应包括新的客户端凭据:

{
"client_id": "a1b2c3d4e5f6",
"client_secret": "secret_xyz789...",
"client_id_issued_at": 1737799294,
"client_secret_expires_at": 0,
"redirect_uris": ["http://localhost:3000/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "none",
"application_type": "native"
}

请安全地存储 client_id 和 client_secret——您将在后续所有 OAuth 流程中用到它们。

请求参数​

您的注册请求需要至少一个重定向 URI。其他一切均为可选,Casdoor会应用合理的默认值:

  • redirect_uris(必填):允许的回调 URL 数组,Casdoor 在认证后会重定向至此
  • client_name: 用于你的应用程序的显示名称(如果省略则自动生成)
  • grant_types: OAuth 授权类型,您的应用将使用——默认为 ["authorization_code"]
  • token_endpoint_auth_method: 您的应用程序在令牌端点的认证方式(none、client_secret_post 或 client_secret_basic)
  • application_type: 对于服务器端应用,选择 web;对于桌面/移动应用,选择 native
  • logo_uri: 您应用程序的Logo的URL
  • client_uri: 您应用程序主页的URL
  • scope:您的应用请求的OAuth作用域列表,以空格分隔

通过DCR创建的应用程序具有7天的令牌有效期,并在管理界面中标记为dcr,以便于识别。

管理已注册的客户端​

Casdoor 还实现了 RFC 7592,客户端可以通过 /api/oauth/register/{client_id} 读取、更新或删除自己的注册信息:

  • GET /api/oauth/register/{client_id}:读取客户端当前的元数据。
  • PUT /api/oauth/register/{client_id}:更新客户端的元数据。
  • DELETE /api/oauth/register/{client_id}:删除客户端。

按组织控制DCR​

组织通过组织配置页上的 dcrPolicy 设置决定是否开放 DCR。支持两个值:

  • disabled(默认):注册请求会被拒绝并返回错误。 dcrPolicy 未设置或为空时同样视为禁用,所以 除非你明确开启,DCR 一直是关闭的。 Casdoor 的内置组织默认禁用 DCR。
  • open:任何人都可以不经认证在这个组织中注册应用。

这样可以灵活处理:对面向开发者的组织开启 DCR,对需要人工把关的生产环境保持关闭。由于默认关闭,在你主动开启之前,不会暴露任何无需认证的注册接口。

安全模型​

注册接口本身不需要认证,这是有意设计的,为的是移动应用、桌面工具这类在注册前无法安全保存凭据的公共客户端。为了避免这个无需认证的入口被意外暴露,DCR 默认禁用,需要按组织单独开启(见 按组织控制 DCR)。

通过DCR创建的应用程序属于组织的管理员账户,并会在您的应用程序列表中显示带有dcr标签。这个标签不只是个标记:通过 DCR 注册的应用以受限的 app-dcr 角色运行,只能访问登录流程需要的 OAuth/OIDC 接口(/api/login/oauth/*、/api/get-oauth-token、/api/userinfo、/api/get-application)。它们不能用客户端凭据调用其他管理 API,从而限制了自助注册客户端可能造成的影响范围。

为了让最终用户真的能登录自助注册的应用,通过 DCR 注册的应用会启用密码登录,并从组织的默认应用继承一组字段:

  • 提供商和登录方式:保证开箱就至少有一种可用的登录方式。
  • 品牌:Logo(仅当请求中没有 logo_uri 时)、主题、页脚 HTML 和表单 CSS,让登录页和组织其他部分风格一致。
  • 登录项:与默认应用相同的登录表单布局。
  • EnableSigninSession 和 EnableWebAuthn:默认应用的会话和 WebAuthn 设置。

默认情况下,客户端密钥不会过期,但您可随时通过管理界面撤销任何应用程序。对于生产部署,考虑一下您的组织是否真的需要未经过身份验证的注册。很多场景手动创建应用就够了,保持 DCR 关闭可以少一个被滥用的入口。

完整示例:MCP 客户端​

以下是 MCP 客户端从零开始实现 DCR 的方法:

// Discover the registration endpoint
const discovery = await fetch('https://your-casdoor.com/.well-known/openid-configuration')
.then(r => r.json());

// Register the application
const registration = await fetch(discovery.registration_endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_name: 'MCP Client',
redirect_uris: ['http://127.0.0.1:6437/callback'],
grant_types: ['authorization_code', 'refresh_token'],
token_endpoint_auth_method: 'none',
application_type: 'native'
})
}).then(r => r.json());

// Store credentials for OAuth flows
const { client_id, client_secret } = registration;

使用这些凭据,客户端将按照标准的OAuth授权码流程进行操作。用户在浏览器中进行身份验证,Casdoor 会将授权码重定向回您的回调 URL,您再用该授权码换取访问令牌。

处理注册失败​

当出现错误时,Casdoor会返回符合RFC 7591规范的错误,并附带一个error代码和便于人类阅读的error_description。最常见的问题:缺少重定向 URI(invalid_redirect_uri)、参数格式错误(invalid_client_metadata),或组织的 DCR 已禁用(access_denied)。请查看描述字段,了解需要修复的具体问题。