如需直接访问 zeuz 基础 API,您必须编写脚本来登录 zeuz 并生成请求哈希,进而用请求哈希来创建会话密钥并附到您的 API 请求上。会话密钥的有效期为 24 小时。
下列步骤和 C++ 代码示例向您展示了登录脚本中必须包含的内容,其中涵盖了 API 认证 中的任务 3. 登录 zeuz 并生成会话密钥。
关于 API 认证 中,涵盖任务 3. 登录 zeuz 并生成会话密钥 和任务 4. 生成签名哈希并附在 API 请求上 的完整工作示例,请参阅 示例代码 。
警告:登录脚本不是必须的。
请参阅下方的 我是否需要登录脚本?
资讯:我是否需要登录脚本?
在开始之前,请参阅 API 简介,检查您是否可以使用 SDK 下载中提供的封装之一或 Go SDK 来访问 zeuz API。如果您可以使用封装或 Go SDK,就不需要自己编写认证脚本。
在下列情况下,您必须直接访问 zeuz 基础 API:
- 您不使用 Unity、虚幻引擎或 Go 开发游戏。
- 您想调用 zeuz API 为您的游戏建立工具,例如,将您的游戏集成到 CI/CD 管道中。
前期准备
在开始创建登录脚本之前,请确保您已经:
阅读 zeuz API 的介绍信息。
请参阅 API 简介。
阅读 zeuz 基础 API 的认证过程,了解需要完成哪些设置。
请参阅 API 认证。
有权访问与您的 zeuz 账号相关联的开发人员资料。
生成 API 密钥 (取决于您访问 API 的方式)。
如果您想从您的游戏或游戏以外的服务中调用 zeuz 基础 API (例如,管理负载),请生成一个 API 密钥。
我们建议您为要执行的每项任务单独生成一个 API 密钥。
详情请参阅 API 密钥。
检查本地开发机上的时钟设置是否正确。
如果时钟设置不正确,认证可能会失败并返回 request expired
错误。
关于错误处理的示例,请参阅 步骤4 - 调用 auth_login 端点 中的代码。
获得开发人员的登录信息和 / 或 API 密钥和 API 密码之后,请在登录脚本中执行下列步骤:
步骤 1 - 生成 nonce 和时间戳
编写一个函数以生成 nonce (仅供一次性使用的数字) 和时间戳。该函数将用于 步骤 3 - 创建并编码请求哈希。
关于 zeuz 时间戳的更多信息,请参阅 时间处理。
C++ 代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| #include <chrono>
#include <string>
#include <unistd.h>
// 生成指定长度的 nonce
std::string generate_nonce(const int len) {
std::string tmp_s;
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
srand( (unsigned) time(NULL) * getpid());
tmp_s.reserve(len);
for (int i = 0; i < len; ++i) {
tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)];
}
return tmp_s;
}
// 生成当前时间的 zeuz 时间戳
// 更多信息,请参阅:See doc.zeuz.io/docs/time-handling
long zeuz_now() {
auto now = std::chrono::system_clock::now();
auto now_ms = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto epoch = now_ms.time_since_epoch();
return (epoch.count() + 2208988800) * 1000 * 1000;
}
|
步骤 2 - 创建并编码密码哈希
编写一个函数,使用您的 zeuz 开发人员用户名和密码或 API 密钥和 API 密码,来生成密码哈希。使用开发人员凭证还是 API 凭证取决于您想调用的 API 端点的授权级别。更多信息,请参阅 授权。
该函数 (下列代码示例中的 generate_pwhash
) 必须完成下列工作:
连接 “zeuz” 与您的开发人员用户名或 API 密钥,以创建一个 盐。
将盐与您的开发人员密码或 API 密码一起传递给 脚本 函数以生成脚本哈希值。下列代码示例使用 libscrypt
库。
使用 Base64 编码脚本哈希。
连接 “a” 与编码后的脚本哈希,以创建最终的密码哈希。
C++ 代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| #include <libscrypt.h>
// 使用选中的库执行 Base64 编码。
std::string base64_encode(unsigned char * value, unsigned int length);
// 生成密码哈希。
std::string generate_pwhash(std::string login, std::string password) {
std::string salt = "zeuz" + login;
uint8_t hash[32] = { 0 }; // The output hash is 32 bits long
// 本示例使用 libscrypt-dev 库。
// 运行 sudo apt-get install libscrypt-dev 命令安装该库。
libscrypt_scrypt(
reinterpret_cast<const uint8_t*>(&(password.c_str())[0]),
password.length(),
reinterpret_cast<const uint8_t*>(&(salt.c_str())[0]),
salt.length(),
1024,
8,
1,
hash,
32);
return "a" + base64_encode((unsigned char *) hash, 32);
}
|
步骤 3 - 创建并编码请求哈希
编写一个函数,将 nonce、时间戳和密码哈希值合并为一个称为请求哈希的哈希值,然后使用 Base64 编码请求哈希。
下列图片使用下方示例代码中的函数名和变量名,概述了请求哈希的创建流程:

图像:请求哈希创建流程
下方示例代码中使用的函数为 zeuz_hash
,该函数将用于 步骤 5 - 创建会话密钥。已使用图例阐明该函数涉及的参数和返回值。
C++ 代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| // 使用安全哈希算法 SHA3-256 对输入字符串进行哈希。
void sha3_256_hash(const char * value, int length, unsigned char ** output, unsigned int * output_length);
// 使用 Base64 对输入字符进行编码。
std::string base64_encode(unsigned char * value, unsigned int length);
// 使用安全哈希算法 SHA3-256 对输入字符串进行哈希。
// 使用 Base64 对其进行编码并返回编码后的值。
std::string zeuz_hash(std::string value) {
unsigned char * hash;
unsigned int hash_length;
sha3_256_hash(value.c_str(), value.length(), &hash, &hash_length);
std::string base64_hash = base64_encode(hash, hash_length);
return base64_hash;
}
// 生成指定长度的 nonce。
auto nonce = generate_nonce(10);
// 生成当前时间的 zeuz 时间戳。
// See doc.zeuz.io/docs/time-handling for more information
auto now = zeuz_now();
// 生成密码哈希。
auto pwhash = generate_pwhash(login, password);
// 将 nonce、时间戳和密码哈希组成请求哈希。
auto request_hash = zeuz_hash(nonce + std::to_string(now) + pwhash);
|
步骤 4 - 调用 auth_login 端点
调用 auth_login
API 端点,使用上述步骤中的请求哈希登录 zeuz。您必须用 POST 方法把 JSON 格式的登录信息发送给 zeuz。
此外您还必须提供 auth_login
所需的其他属性。关于端点属性的详情,请参阅 API 参考中的 auth_login。
zeuz 在您创建开发人员资料和 / 或 API 密钥时生成了一个密码哈希值,并使用该密码哈希与您在 auth_login
中提供的 nonce 和时间戳,创建一个请求哈希。如果该请求哈希值与上述步骤中生成的请求哈希值相匹配,zeuz 会判定登录有效。反之,如果不匹配,zeuz 会拒绝该登录请求。
如果登录成功,zeuz 会向执行登录的函数发送一些信息,其中包含下列内容:
会话 ID:用于识别会话的唯一值。在之后的请求中会用到。
更多信息,请参阅 API 认证。
注意:之后的请求指的是登录后在同一个登录会话内执行的 API 请求。
会话 nonce:新的仅供一次性使用的随机字符串。
ValidThru:会话过期的日期 / 时间。
从您的脚本中取出这些值,用于之后的 API 请求。
C++ 代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| // 用 JSON 格式化您的登录数据。
Json::Value data;
Json::FastWriter writer;
data["Time"] = Json::Int64(time);
// 请求哈希。
data["Data"]["Hash"] = hash;
data["Data"]["IsApi"] = true;
data["Data"]["IsUser"] = false;
data["Data"]["Login"] = login;
// Nonce。
data["Data"]["Nonce"] = nonce;
// 时间戳。
data["Data"]["Time"] = Json::Int64(time);
auto json = writer.write(data);
// 在 HTTP POST 请求体中向zeuz API发送数据。
// auth_login 端点。
auto response = post_request("https://zcp.zeuz.io/api/v1/auth_login", json);
// 解析 JSON 响应。
Json::Reader reader;
Json::Value response_json;
if (!reader.parse(response, response_json)) {
// 解析失败则报错。
// 注意:在生产代码中,使用 C++ 异常来替代。
throw std::string("could not parse response data ( " + response + ")");
}
// 检查是否设置错误字段。
auto error = response_json["Error"].asString();
if (!error.empty()) {
// 如果错误以 request_expired 开头,
// 说明生成的时间戳已过期。
if (error.rfind("request_expired", 0) == 0) {
// 注意:在生产代码中,您可以重试登录,
// 或确保系统时间是正确的。
throw std::string("verify system clock or retry request");
} else {
// 出现异常错误。认证信息可能有误。
// 注意:在生产代码中,使用 C++ 异常来替代。
throw std::string("could not login (" + response + ")");
}
}
// 提取会话 ID、会话 nonce 和
// 会话到期的时间 (ValidThru)。
// of session expiry (ValidThru)
std::string session_id = response_json["Data"]["SessionId"].asString();
std::string session_nonce = response_json["Data"]["SessionNonce"].asString();
std::string valid_thru = response_json["Data"]["ValidThru"].asInt64();
|
注意: 在极少数情况下,会话可能提早于 ValidThru 变量指定的日期 / 时间失效。为防止这种情况,请监测请求的响应代码,如会话提前失效,请重新认证。详情请参阅 错误处理。
步骤 5 - 创建会话密钥
现在您需要创建一个会话密钥。如需创建会话密钥,请使用您在 步骤 3 中创建的函数 (代码示例中的 zeuz_hash
),将您在 步骤 4 中从 zeuz 收到的会话 nonce 与密码哈希结合起来。会话密钥的有效期为 24 小时。
下列图片使用示例代码中的函数名和变量名,概述了回话密钥的创建流程。关于 generate_pwhash
的更多信息,请参阅步骤 2 和步骤 3。

图像:会话密钥创建流程
C++ 代码示例如下:
1
2
| // 将会话 nonce 和密码哈希组合为会话密钥
auto session_key = zeuz_hash(session_nonce + pwhash);
|
下一步:认证 API 请求
现在您已经登录到 zeuz,您可以生成一个签名哈希,并将其附到您的 API 请求中。
如需生成签名哈希,您必须生成一个新的 nonce 和一个新的时间戳,用它们和会话密钥一起生成另一个称为签名哈希的哈希密码,然后用该签名哈希来认证 API 请求,直至会话密钥过期 (会话密钥在创建后 24 小时过期)。
详情请参阅 签名哈希生成,以及生成签名哈希以认证后续 API 请求的示例。
2021年8月9日 该文档已更新并通过审校:添加创建请求哈希和会话密钥的流程图
2021年5月12日 该文档已创建并通过审校