最近由于工作原因又开始捣鼓OceanBase,OceanBase云平台(OCP)提供了强大的管理和监控功能,而且对外开放API接口,可以将部分监控整合到自己的平台,所以写了个Java调用OCP API的demo做为自己的技术储备,也想分享给大家。也因为最近对Eclipse Vertx和异步编程非常兴趣,所以案例使用是Vertx的WebClient,而非Apache HttpClient, 不过,不管用什么库,原理是相似的。
先介绍下环境,我这边用的是OCP企业版4.2.2,OB不同版本之间差异还是很大的,其它版本不一定适用。参考的是官方文档(https://www.oceanbase.com/docs/common-ocp-1000000000585101):云平台OCP --> “参考指南” --> “API参考”。
客户端鉴权
OCP开放API的客户端鉴权,支持使用AK/SK和HTTP Basic两种认证模式。
HTTP Basic认证模式
HTTP Basic通过用户名和密码进行鉴权,相对比较简单,但因为是明文传输,并不安全,特别是使用http时,用户名和密码可以在传输过程中被抓包解析出来。对于可控的内网,也可以做为便捷的方法。以下是实现代码(为了文档更好的阅读,完整的代码放在文章的资源中https://download.csdn.net/download/Li_Xiang_996/89517863?spm=1001.2101.3001.9499)。
// 先构建'"用户名":"用户密码"字符串, 然后将字符进行Base64编码,就可以得到authorization。
byte[] strContents = (userName.trim() + ":" + password.trim()).getBytes();
String base64Contents = Base64.getUrlEncoder().encodeToString(strContents);
String authorization = "Basic " + base64Contents;
// 然后调用API时候,将authorization放到HTTP请求消息头Authorization中即可。
client.something.putHeader("Authorization", authorization).send();
API(AK/SK)认证模式
OB得官方文档有详细介绍如何使用,可以参考。一些题外话,OB的官方文档相较之前有非常巨大的进步,值得点赞。
首先需要在OCP中创建(申请) AK/SK,登录OCP,右边导航点开"系统管理" ->“用户管理”。用户列表中选择一个用户或者创建一个新用户,需要注意的是,当获取了用户的AccessKey,也就获得了该用户的权限。
选择用户,进入对应的用户的设置页面,在“AccessKey”部分,点击"一键创建 AccessKey",即可获取该用户的AK/SK。后续我们就可以通过AK/SK来进行API访问。
认证原理大致是: 客户端将(将要)对API的请求按照指定的格式拼接成一个消息(字符串),然后用申请到的AK对应的SK,通过HMACSHA1算法对消息进行加签(生成消息的哈希串)。
//// 消息体格式
String message =
"POST\n" + //HTTP请求方法, 大写英文。包括: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS和TRACE。
"186974DB33A090A16D3E2CA35F547B56\n" + // 请求体, md5编码, 可以为空(如使用HTTP GET时候), 当换行(\n)符号不能省略。
"application/json\n" + // 消息体的类型。OCP统一使用application/json类型的消息体。
"Fri, 5 Jul 2024 06:49:37 GMT\n" + // 请求发起时间, 其遵循RFC1123格式, 必须是GMT时区?
"10.100.6.161:8080\n" + // OCP服务器地址+端口
"x-ocp-date:Fri, 5 Jul 2024 06:49:37 GMT\n" + //
"/api/v2/compute/idcs" //API请求的路径, 以及请求的查询参数, 请求参数可以为空, 如果有多个必须按参数名(升序排序), 否则无法通过验证
//// hmacSha1加签
byte[] hash = hmacSha1(accessKeySecret, message.getBytes(StandardCharsets.UTF_8));
String signature = Base64.getEncoder().encodeToString(hash);
String authorization = "OCP-ACCESS-KEY-HMACSHA1 " + accessKey + ":" + signature;
// 然后调用API时候,将authorization放到HTTP请求消息头Authorization中即可。
client.something.putHeader("Authorization", authorization).send();
服务器端行为没看过代码, 纯属个人猜测, 看个乐吧:服务器端(数据库中)保存了用户AK/SK表, 服务器根据接收到请求的Authorization, 可获取客户端的AK,就可以查询到关联用户,即可进行权限检查(是否有权执行); 进一步取出对应的SK,根据服务器获取的客户端请求(通过客户端相同的格式)构建消息体, 并使用SK和相同的HASH算法(HMACSHA1)对消息体进行加签(计算HASH),如果两者签名相同, 那么这通过验证,返回结果,类似于证书的校验过程。</