如何用oauth4cj扩展新的授权服务器:10分钟手写一个自定义API类
2026/9/24 14:18:02 网站建设 项目流程

如何用oauth4cj扩展新的授权服务器:10分钟手写一个自定义API类

【免费下载链接】oauth4cj一个Oauth开放授权协议库,Open Authorization的缩写项目地址: https://gitcode.com/Cangjie-TPC/oauth4cj

oauth4cj 是一个支持 OAuth 1.0 和 OAuth 2.0 的 Cangjie 开源授权协议库,允许第三方程序通过访问令牌访问受保护资源,而无需暴露用户凭据。想接入 Gitee、GitHub、微博、华为等任意授权服务器?本文带你10 分钟手写一个自定义 API 类,把任何 OAuth 授权服务器接入 oauth4cj 的授权码、密码、客户端、简化四种模式,全程只需继承一个基类、实现几个方法。

上图展示了 oauth4cj 遵循的标准 OAuth 授权流程:客户端(Application)向用户发起授权请求,经授权服务器(Authorization Server)颁发访问令牌(Access Token),最终调用资源服务器(Resource Server)获取受保护资源。你要做的,就是告诉 oauth4cj 你的授权服务器"端点在哪里、怎么认证、令牌怎么解析"——这正是自定义 API 类要回答的 4 个问题。

为什么扩展新授权服务器只需要写一个类

oauth4cj 采用"默认实现 + 策略扩展"的设计:

  • oauth_service.cj 定义了 OAuth 服务的公共骨架(请求执行、关闭、HTTP 客户端等);
  • default_api20.cj 是OAuth 2.0 的扩展基类,已内置绝大多数默认行为;
  • 你只需继承它,把"每个平台不同的部分"填上即可。

基类中必须实现(abstract)的方法只有 2 个,其余方法都提供了默认实现,按需覆盖:

方法作用默认实现?
getAccessTokenEndpoint()令牌请求端点 URL❌ 必须实现
getAuthorizationBaseUrl()用户授权页面 URL❌ 必须实现
getAccessTokenVerb()令牌请求的 HTTP 方法✅ 默认 POST
getRefreshTokenEndpoint()刷新令牌端点✅ 默认同令牌端点
getClientAuthentication()客户端身份认证方式✅ 默认 HTTP Basic
getBearerSignature()access_token 附加到请求的位置✅ 默认放在 Header
getAccessTokenExtractor()解析令牌响应体✅ 默认 JSON 解析
getDeviceAuthorizationEndpoint()设备授权端点(RFC 8628)❌ 不支持则抛异常

💡 规律总结:一个平台的 OAuth 文档里通常只写 4 个信息——授权 URL、令牌 URL、认证方式、响应格式。这 4 个信息恰好对应上表的 4 个方法。

10分钟手写自定义API类:完整步骤

第 1 步:阅读目标平台的 OAuth 文档

打开你的授权服务器(下例假设是某平台oauth.example.com)的开发者文档,抄下 4 个信息:

  1. 授权页面https://oauth.example.com/authorize
  2. 令牌端点https://oauth.example.com/oauth/token(POST)
  3. 客户端认证client_id/client_secret放在请求体中
  4. 令牌响应:标准 JSON(access_tokenexpires_inrefresh_token…)

第 2 步:继承 DefaultApi20 写你的 API 类

只需 30 行代码(对照 default_api20.cj 的方法签名):

/* * 准备 OAuth 2.0 的默认实现: * 继承 DefaultApi20,实现抽象方法,覆盖不同的提取器或服务。 */ public class ExampleApi <: DefaultApi20 { protected init() { } public static func instance(): ExampleApi { return ExampleApi() } //返回请求类型(默认就是 POST,这里显式写出让读者直观) public func getAccessTokenVerb(): Verb { return Verb.POST } //接收访问令牌请求的 URL public func getAccessTokenEndpoint(): String { return "https://oauth.example.com/oauth/token" } //用户授权页面链接 protected func getAuthorizationBaseUrl(): String { return "https://oauth.example.com/authorize" } //客户端认证:client_id/client_secret 写入请求主体 public func getClientAuthentication(): ClientAuthentication { return RequestBodyAuthenticationScheme.instance() } //access_token 通过 URI 查询参数附加到请求中 public func getBearerSignature(): BearerSignature { return BearerSignatureURIQueryParameter.instance() } }

注意两点:

  • getAccessTokenExtractor()不用写——默认返回 OAuth2AccessTokenJsonExtractor,绝大多数平台返回的都是标准 JSON;
  • 你的平台若要求 token 放在 Header(Authorization: Bearer xxx),则getBearerSignature()可省略,默认即是该行为,见 bearer_signature.cj。

第 3 步:用 ServiceBuilder 构建服务

在 service_builder_oauth20.cj 的建造者模式中,把自定义 API 类作为build()参数传入:

let service: OAuth20Service = ServiceBuilderOAuth20(clientId). setApiSecret(clientSecret). setDefaultScope("profile emails"). setCallback(redirect_uri). build(ExampleApi.instance()) // 👈 关键:注入自定义 API 类

第 4 步:跑通授权码模式(以 oauth20_service.cj 的接口为例)

//1. 生成可获取授权码的链接 let authorizationUrl: String = AuthorizationUrlBuilder(service). setState("secret").build() //2. 用回调拿到的一次性授权码 code,换取访问令牌 let accessToken: OAuth2AccessToken = service.getAccessToken(code) //3. 签名并请求受保护资源 let request: OAuth4cjRequest = OAuth4cjRequest(Verb.GET, protectedResourceUrl) service.signRequest(accessToken, request) let response: OAuth4cjResponse = service.execute(request)

至此,你的授权服务器已完整接入。其他模式同样直接可用:

  • 密码模式service.getAccessTokenPasswordGrant(username, password)
  • 客户端模式service.getAccessTokenClientCredentialsGrant()
  • 刷新令牌service.refreshAccessToken(accessToken.getRefreshToken())
  • 设备授权(RFC 8628):覆盖getDeviceAuthorizationEndpoint()后调用service.getDeviceAuthorizationCodes()

平台差异速查:该覆盖哪个方法

平台差异需要覆盖的方法
令牌响应不是 JSON(如简化模式返回access_token=xxx&expires_in=xxx纯文本)getAccessTokenExtractor(),参考 oauth2_access_token_extractor.cj
刷新令牌端点独立于令牌端点getRefreshTokenEndpoint()
支持令牌吊销(RFC 7009)getRevokeTokenEndpoint()
令牌请求要求 GET(如腾讯简化模式)getAccessTokenVerb()返回Verb.GET
支持设备授权授予(RFC 8628)getDeviceAuthorizationEndpoint()

官方文档中的 Gitee、华为、腾讯示例就是同一套模板的不同填法,可直接在 README.md 的"功能示例"章节对照阅读。

常见问题

Q1:自定义 API 类要单例吗?不是必须,但示例代码统一提供了static func instance()方便复用。

Q2:OAuth 1.0a 平台怎么扩展?同样思路:继承 default_api10a.cj 基类,用 service_builder_oauth10a.cj 构建服务。

Q3:请求失败报 401 通常是哪里出了问题?优先检查getClientAuthentication()与平台要求的认证方式是否一致(Body 传参 vs HTTP Basic 头)。

参考资料

  • 完整接口说明:doc/feature_api.md
  • 各平台功能示例与编译构建说明:README.md
  • 版本变更记录:CHANGELOG.md

动手试试吧:找到你常用的一个授权平台的 OAuth 文档,照上表填 4 个信息,10 分钟后你就会得到一个能跑通授权码模式的自定义 API 类。

【免费下载链接】oauth4cj一个Oauth开放授权协议库,Open Authorization的缩写项目地址: https://gitcode.com/Cangjie-TPC/oauth4cj

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询