鉴权说明
签名流程
在sdk的init方法中,需要用户传入一个签名。下面介绍该签名的产生流程:
第一步:构造规范化请求字符串
请按照如下规则构造规范化请求字符串:
a=[api_key]&b=[expire_time]&c=[current_time]&d=[random]
其中:
- api_key:用户在FaceID控制台可以申请
- expire_time:签名的有效期,是一个符合 UNIX Epoch 时间戳规范的数值,单位为秒。单次签名时,设置为0。
- current_time:生成签名时的时间戳,单位为秒。非单次签名时,current_time需要小于expire_time。
- random:用户自行产生的一个10位无符号随机数。
第二步:生成签名
计算规范化请求字符串的HMAC-SHA1值,并和规范化请求字符串拼接后进行base64编码,公式如下:
raw = "a={}&b={}&c={}&d={}".format(api_key, expire_time, current_time, random)
sign_tmp = hmac.new(api_secret, raw, hashlib.sha1).digest()
sign = base64.b64encode(sign_tmp + raw)
最佳实践:
为了安全起见,我们建议签名生成放在用户服务器端进行,而不放在客户端。用户在调用FaceID SDK前,需要先和自己的业务服务器进行一次通信,获取签名。在SDK的初始化方法中,需要传入该签名值。
用户服务端的例子代码参见:
- python版本
import time
import hashlib
import base64
import random
import hmac
# 下面api_key,api_secret请更换为开发者在FaceID平台申请的api_key,api_secret
api_key = "ICVvC_xUs6177WEtyUNwIH8J6NfGu50t"
api_secret = "UjYGdN9CBZKsDBLB5-5v3DykPXY6dw3q"
valid_durtion = 100 # 有效时间100秒
current_time = int(time.time())
expire_time = current_time + valid_durtion
rdm = ''.join(random.choice("0123456789") for i in range(10))
raw = "a={}&b={}&c={}&d={}".format(api_key, expire_time, current_time, rdm)
# raw = "a=ICVvC_xUs6177WEtyUNwIH8J6NfGu50t&b=1530762218&c=1530762118&d=0799687066"
sign_tmp = hmac.new(api_secret, raw, hashlib.sha1).digest()
sign = base64.b64encode(sign_tmp + raw)
# sign = "SPzLRbDBgTGC2A8YdDaa7Jrny+5hPUlDVnZDX3hVczYxNzdXRXR5VU53SUg4SjZOZkd1NTB0JmI9MTUzMDc2MjIxOCZjPTE1MzA3NjIxMTgmZD0wNzk5Njg3MDY2"
- java版本
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Random;
public class HmacSha1Sign {
/**
* 生成签名字段
*
* @param apiKey
* @param secretKey
* @param expired
* @return
* @throws Exception
*/
public static String genSign(String apiKey, String secretKey, long expired) throws Exception {
long now = System.currentTimeMillis() / 1000;
int rdm = Math.abs(new Random().nextInt());
String plainText = String.format("a=%s&b=%d&c=%d&d=%d", apiKey, now + expired, now, rdm);
byte[] hmacDigest = HmacSha1(plainText, secretKey);
byte[] signContent = new byte[hmacDigest.length + plainText.getBytes().length];
System.arraycopy(hmacDigest, 0, signContent, 0, hmacDigest.length);
System.arraycopy(plainText.getBytes(), 0, signContent, hmacDigest.length,
plainText.getBytes().length);
return encodeToBase64(signContent).replaceAll("[\\s*\t\n\r]", "");
}
/**
* 生成 base64 编码
*
* @param binaryData
* @return
*/
public static String encodeToBase64(byte[] binaryData) {
String encodedStr = Base64.getEncoder().encodeToString(binaryData);
return encodedStr;
}
/**
* 生成 hmacsha1 签名
*
* @param binaryData
* @param key
* @return
* @throws Exception
*/
public static byte[] HmacSha1(byte[] binaryData, String key) throws Exception {
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
mac.init(secretKey);
byte[] HmacSha1Digest = mac.doFinal(binaryData);
return HmacSha1Digest;
}
/**
* 生成 hmacsha1 签名
*
* @param plainText
* @param key
* @return
* @throws Exception
*/
public static byte[] HmacSha1(String plainText, String key) throws Exception {
return HmacSha1(plainText.getBytes(), key);
}
}
- php版本
<?php
function gen_sign($apiKey, $apiSecret, $expired){
$rdm = rand();
$current_time = time();
$expired_time = $current_time + $expired;
$srcStr = "a=%s&b=%d&c=%d&d=%d";
$srcStr = sprintf($srcStr, $apiKey, $expired_time, $current_time, $rdm);
$sign = base64_encode(hash_hmac('SHA1', $srcStr, $apiSecret, true).$srcStr);
return $sign;
}