本文基于海康综合安防管理平台iSecure Center V1.4版本开发,海康官方sdk中只提供java/C#/C C++版本的OpenAPI程序包https://open.hikvision.com/download/5c67f1e2f05948198c909700?type=10,暂未提供Python版本,而自己的项目是基于Python框架开发,虽然有前序的Jpype调用Java版本的sdk,但不尽完美,于是有了此文。
海康官方给出的OpenAPI通信认证含有ca签名认证和token认证两种方式,但token的获取必须是通过ca认证方式得到,所以万里行程第一步便是ca证书认证问题。
在海康综合安防管理平台的管理中心可得到app_key,app_secret,如下:
运行管理中心的IP类似 http://192.168.45.8:8001/center/ 运行管理中信息的状态监控下的center management server 中的API网关中的API管理。
海康OpenAPI签名公式
X-Ca-Signature=BASE64(HmacSHA256(appSecret,"UTF-8"(httpHeaders + customHeaders + url));
更多详细内容见 https://open.hikvision.com/docs/6a14a251f6d042319b277b26ad60aa17 python代码如下:
def sign(key, value):
temp = hmac.new(key.encode(), value.encode(), digestmod=hashlib.sha256)
rreturn (base64.b64encode(temp.digest()).decode())
header中的ca签名如下:
x_ca_nonce = uuid.uuid4()
x_ca_timestamp = int(round(time.time()) * 1000)
sign_str = ("POST\n*/*\napplication/json\nx-ca-key:{key}\nx_ca_nonce:{nonce}\n"
"x_ca_timestamp:{timestamp}\n{method}").format(key=self.hk_app_key,
timestamp=x_ca_timestamp,
nonce=str(x_ca_nonce), method=method)
# 此处有坑 不要使用"POST\n"+"*/*\napplication/json\n" 这样的方式拼串,虽然肉眼可见是一样的,但执行的sign结果却不一样,真的很酸爽
signature = sign(self.hk_app_secret, sign_str)
最终的header是这样的:
header = {
'Accept': '*/*',
'Content-Type': 'application/json',
'X-Ca-Signature-Headers': 'x-ca-key,x_ca_nonce,x_ca_timestamp',
'x-ca-key': self.hk_app_key,
'x_ca_nonce': str(x_ca_nonce),
'x_ca_timestamp': str(x_ca_timestamp),
'X-Ca-Signature': signature,
}
try:
url = self.url.format(method=method)
response = requests.post(url, data=json.dumps(body), headers=header) #header见上文
if response.status_code == 200:
ret = json.loads(response.text)
result = {
"status": 200,
"message": ret.get('data')
}
else:
result = {
"status": response.status_code,
"message": response.reason
}
except Exception as e:
result = {
"code": 500,
"message": e.message
}
return result
def get_preview_url(self, idx_code):
method = "/artemis/api/video/v2/cameras/previewURLs"
body = {
"cameraIndexCode": idx_code,
"streamType": 1,
"protocol": "hls",
"transmode": 0,
"expand": "streamform=ps",
"streamform": "ps"
}
return self.request_post(method, body)
虽然sign看着很简单,但在自己实践过程中遇到了两个坑,上文中的字符串拼接是一个,这个的解决是根据海康的返回值StringToSign,即海康根据你的header中的信息在服务端进行签名计算,计算的结果如果跟你的X-Ca-Signature中的一致那就ok.第二个就是sign本身,刚开始位数都不对,这个是反编译海康的sdk逐步调试出的sign函数。一句话,明白了其中原理在coding才不迷茫。
本想代码上传github 无奈被墙 就在gitlab上公开代码片段
https://gitee.com/mabinmt/codes/cy41f2ltmxs6n8ovwgbj351