本文将描述在线授权
基本概念和操作流程,读完本文您将对在线授权机制有全面的了解,并且学会如何顺利的通过在线授权机制使用我们的软件。
软件证书
是软件使用权的凭证,一个合法的软件证书有以下特性:
软件证书一般以文件的形式存在设备文件系统中。
在线授权
是一种软件证书
的网络分发方式,通过这个机制,设备可以快速、安全的通过网络获取软件证书。
在线授权不是唯一的证书分发方式。例如,您依然可以通过联系商务人员以人工审核+电子邮件的方式获取软件证书。相较人工途径,在线证书可以更高效的完成授权流程,在自动化的同时保证安全性。
下图展示了一次在线授权流程
从SDK 获取authMsg
//bef_effect_ai_auth_msg.h bef_effect_ai_get_auth_msg( char** buf, int* len)
构造消息体,发送请求到字节跳动在线授权服务
URL:https://cv-tob.bytedance.com/v1/api/sdk/tob_license/getlicense
HTTP 方法:POST
内容格式:JSON
消息示例:
POST /v1/api/sdk/tob_license/getlicense HTTP/1.1 Host: cv-tob.bytedance.com Content-Type: application/json { "key": <key>, "authMsg": <authMsg>, "nonce": <nonce>, "timestamp": <timestamp>, "digest": <digest> }
字段解释:key
:业务标识,对应用户开通的业务类型。authMsg
:验证消息,由SDK 产生的设备相关标识。nonce
:随机数。timestamp
:unix 时间戳(从1970/1/1 到当前的秒数)digest
:数字签名,见以下描述。
为了保障消息的权威性和完整性,这里使用HMAC_SHA256
作为签名算法
digest = HMAC_SHA256(<secret>, key + nonce + timestamp + aughMsg)
secret
:业务密钥,创建业务时候同key
一起获得。+
:为字符串拼接操作("a" + "b" = "ab")
授权服务器返回响应消息
消息示例:
//Success { 'data': <base64 encoded license>, 'digest': <digest>, 'status_code': 0 } //Failure { 'error': <error message>, 'status_code': <code> }
若请求成功,则data
为base64 编码的证书内容(要获取证书内容,需base64 解码) digest = HMAC_SHA256(<secret>, data)
其中secret
同步骤2。
若请求失败,则error
为错误提示,code
为对应错误码,请参考常见错误或联系我们。
将获取的证书设置到SDK 以激活相关模块
Python
def getLicense(key, secret, authMsg): payload = { "key": key, "authMsg": authMsg, "nonce": random.randint(0, 999999999), "timestamp": int(time.time()) } payload['digest'] = crypto.HMAC_SHA256(secret, bytes(key + str(payload['nonce']) + str(payload['timestamp']) + authMsg).encode('utf-8')) url = "https://cv-tob.bytedance.com/v1/api/sdk/tob_license/getlicense" headers = { 'Content-Type': "application/json", 'cache-control': "no-cache" } response = requests.request("POST", url, data=json.dumps(payload), headers=headers) resp_json=json.loads(response.text) print("{}".format(resp_json['data'])) raw = base64.b64decode(resp_json['data']) print('{}'.format(raw)) a = resp_json['data'] b = resp_json['digest'] h = crypto.HMAC_SHA256(secret,a) if h == b: print("crypto.HMAC_SHA256 match") print('getLicense !')
c++
#include <openssl/hmac.h> #include <openssl/sha.h> #include <curl/curl.h> //获取HMAC_SHA256 数字签名 std::vector<uint8_t> HMAC_SHA256(const std::vector<uint8_t>& key ,const std::vector<uint8_t>& value) { unsigned int len = SHA256_DIGEST_LENGTH; unsigned char hash[SHA256_DIGEST_LENGTH]; size_t keyLen = key.size(); size_t valueLen = value.size(); HMAC_CTX *hmac = HMAC_CTX_new(); HMAC_Init_ex(hmac, (unsigned char*)key.data(), keyLen, EVP_sha256(), NULL); HMAC_Update(hmac, (unsigned char*)value.data(), valueLen); HMAC_Final(hmac, hash, &len); HMAC_CTX_free(hmac); return std::vector<uint8_t>((uint8_t*)hash,(uint8_t*)hash+SHA256_DIGEST_LENGTH); } //将二进制内容转换为大写十六进制字符串 std::string hexitize(const std::vector<unsigned char>& input, const char* const digits = "0123456789ABCDEF") { std::ostringstream output; for (unsigned char gap = 0, beg = input[gap]; gap < input.size(); beg = input[++gap]) { output << digits[beg >> 4] << digits[beg & 15]; } return output.str(); } //使用CURL 进行请求 int request_license( const char* key, const char* secret, const char* authMsg, char** license, int* size) { CURL *curl; CURLcode res; curl = curl_easy_init(); std::string readBuffer; auto payload_str = _get_request_content(key, secret, authMsg); if(curl) { curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(curl, CURLOPT_URL, "https://cv-tob.bytedance.com/v1/api/sdk/tob_license/getlicense"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload_str.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); res = curl_easy_perform(curl); } curl_easy_cleanup(curl); if (readBuffer.length() > 0) { auto ret = json::parse(readBuffer); int code = ret["status_code"]; if (code != 0) { std::string msg = ret["error"]; *license = new char[msg.length()+1]; memcpy(*license, msg.c_str(), msg.length()+1); *size = msg.length(); return code; } std::string lic = ret["data"]; std::string digest = ret["digest"]; //verify digest auto re_hash = HMAC_SHA256( Misc::concat(secret, ""), Misc::concat(lic, "") ); if (hexitize(re_hash).compare(digest) == 0) { vector<uint8_t> lic_b = base64_decode(lic); *license = new char[lic_b.size()]; memcpy(*license, lic_b.data(), lic_b.size()); *size = lic_b.size(); return code; } //digest verified failure, corrupted message const char m[] = "Detecting data corruption, please reissue the request."; *license = new char[strlen(m)+1]; *size = strlen(m); memcpy(*license, m, (*size)+1); return -1; } *license = nullptr; *size = 0; return res; }
详见错误码表