本文基于海康综合安防管理平台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

    在海康综合安防管理平台的管理中心可得到app_key,app_secret,如下:

运行管理中心的IP类似 http://192.168.45.8:8001/center/  运行管理中信息的状态监控下的center management server 中的API网关中的API管理。

  • CA认证

海康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

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐