first commit

This commit is contained in:
zxbit2011
2020-11-27 14:26:50 +08:00
commit ee1693bf9e
4 changed files with 360 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
*.log
.idea/

85
README.md Normal file
View File

@@ -0,0 +1,85 @@
# hikvisionOpenAPIGo
> 海康威视OpenAPI安全认证库 - Golang版本实现
# 官网
接口调用认证https://open.hikvision.com/docs/7d0beeded66543999bff7bc2f91414d4
其他语言https://open.hikvision.com/download/5c67f1e2f05948198c909700?type=10
# 快速使用
````
> go get github.com/zxbit2011/hikvisionOpenAPIGo
````
# 示例代码
````
func TestSDK(t *testing.T) {
hk := hikvisionOpenAPIGo.HKConfig{
Ip: "127.0.0.1",
Port: 443,
AppKey: "28057000",
Secret: "dZztQSS0000kLpURG000",
IsHttps: true,
}
body := map[string]string{
"pageNo": "1",
"pageSize": "100",
}
result, err := hk.HttpPost("/artemis/api/resource/v1/cameras", body, 15)
if err != nil {
t.Fatal(err)
return
}
t.Log("OK", string(result))
}
````
# 输出结果
````
TestSDK: sdk_test.go:26: OK {
"code": "0",
"msg": "success",
"data": {
"total": 1,
"pageNo": 1,
"pageSize": 100,
"list": [{
"altitude": 0.0,
"cameraIndexCode": "01c1e8bd1b0d406a94e7cdf88a251f9b",
"cameraName": "cameraTest",
"cameraType": 0,
"cameraTypeName": "枪机",
"capabilitySet": "event_vss,io,vss,record,ptz,remote_vss,maintenance,status",
"capabilitySetName": "视频事件能力,IO能力,视频能力,录像能力,云台能力,视频设备远程获取能力,设备维护能力,状态能力",
"intelligentSet": null,
"intelligentSetName": null,
"channelNo": "1",
"channelType": "analog",
"channelTypeName": "模拟通道",
"createTime": "2020-11-17T18:13:08.935+08:00",
"encodeDevIndexCode": "0d983edda2694411ac15fa64bf29a8ca",
"encodeDevResourceType": null,
"encodeDevResourceTypeName": null,
"gbIndexCode": null,
"installLocation": "",
"keyBoardCode": null,
"latitude": "29.674556",
"longitude": "106.603696",
"pixel": null,
"ptz": null,
"ptzName": null,
"ptzController": null,
"ptzControllerName": null,
"recordLocation": null,
"recordLocationName": null,
"regionIndexCode": "0ceebbf2-b7fd-4e5f-8c02-0d1725643444",
"status": null,
"statusName": null,
"transType": 1,
"transTypeName": "TCP",
"treatyType": null,
"treatyTypeName": null,
"viewshed": null,
"updateTime": "2020-11-24T16:16:41.368+08:00"
}]
}
}
````

38
examples/sdk_test.go Normal file
View File

@@ -0,0 +1,38 @@
package examples
import (
"github.com/zxbit2011/hikvisionOpenAPIGo"
"testing"
)
func TestSDK(t *testing.T) {
hk := hikvisionOpenAPIGo.HKConfig{
Ip: "172.17.207.240",
Port: 443,
AppKey: "28057383",
Secret: "dZztQSSUAF4kLpURGQMa",
IsHttps: true,
}
body := map[string]string{
"pageNo": "1",
"pageSize": "100",
}
result, err := hk.HttpPost("/artemis/api/resource/v1/cameras", body, 15)
if err != nil {
t.Fatal(err)
return
}
t.Log("OK", string(result))
/*body := map[string]string{
"cameraIndexCode": "71c1e8bd1b0d406a94e7cdf88a251f9b",
"protocol": "rtmp",
}
result, err := hk.Post("/artemis/api/video/v2/cameras/previewURLs", body, 15)
if err != nil {
t.Fatal(err)
return
}
t.Log("OK", string(result))*/
}

213
sdk.go Normal file
View File

@@ -0,0 +1,213 @@
package hikvisionOpenAPIGo
import (
"bytes"
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
uuid "github.com/satori/go.uuid"
"io/ioutil"
"net/http"
"sort"
"strings"
"time"
)
// HKConfig 海康OpenAPI配置参数
type HKConfig struct {
Ip string //平台ip
Port int //平台端口
AppKey string //平台APPKey
Secret string //平台APPSecret
IsHttps bool //是否使用HTTPS协议
}
// @title HTTP Post请求
// @url HTTP接口Url string HTTP接口Url不带协议和端口如/artemis/api/resource/v1/org/advance/orgList
// @body 请求参数 map[string]string
// @return 请求结果 参数类型
func (hk HKConfig) HttpPost(url string, body map[string]string, timeout int) (result []byte, err error) {
var header = make(map[string]string)
bodyJson := MustJsonString(body)
hk.initRequest(header, url, bodyJson, true)
var sb []string
if hk.IsHttps {
sb = append(sb, "https://")
} else {
sb = append(sb, "http://")
}
sb = append(sb, hk.Ip)
sb = append(sb, ":")
sb = append(sb, fmt.Sprintf("%d", hk.Port))
sb = append(sb, url)
client := &http.Client{}
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
client.Timeout = time.Duration(timeout) * time.Second
if hk.IsHttps {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client.Transport = tr
}
req, err := http.NewRequest("POST", strings.Join(sb, ""), bytes.NewReader([]byte(bodyJson)))
if err != nil {
return
}
req.Header.Set("Accept", header["Accept"])
req.Header.Set("Content-Type", header["Content-Type"])
for k, v := range header {
if strings.Contains(k, "x-ca-") {
req.Header.Set(k, v)
}
}
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
result, err = ioutil.ReadAll(resp.Body)
} else if resp.StatusCode == http.StatusFound || resp.StatusCode == http.StatusMovedPermanently {
reqUrl := resp.Header.Get("Location")
panic(fmt.Errorf("HttpPost Response StatusCode%dLocation%s", resp.StatusCode, reqUrl))
} else {
err = fmt.Errorf("HttpPost Response StatusCode%d", resp.StatusCode)
}
return
}
// initRequest 初始化请求头
func (hk HKConfig) initRequest(header map[string]string, url, body string, isPost bool) {
header["Accept"] = "application/json"
header["Content-Type"] = "application/json"
if isPost {
header["content-md5"] = computeContentMd5(body)
}
header["x-ca-timestamp"] = MustString(time.Now().UnixNano() / 1e6)
uid, _ := uuid.NewV4()
header["x-ca-nonce"] = uid.String()
header["x-ca-key"] = hk.AppKey
var strToSign string
if isPost {
strToSign = buildSignString(header, url, "POST")
} else {
strToSign = buildSignString(header, url, "GET")
}
signedStr, err := computeForHMACSHA256(strToSign, hk.Secret)
if err != nil {
println(err.Error())
return
}
header["x-ca-signature"] = signedStr
}
// computeContentMd5 计算content-md5
func computeContentMd5(body string) string {
return base64.StdEncoding.EncodeToString([]byte( Md5(body)))
}
// computeForHMACSHA256 计算HMACSHA265
func computeForHMACSHA256(str, secret string) (string, error) {
mac := hmac.New(sha256.New, []byte(secret))
_, err := mac.Write([]byte(str))
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(mac.Sum(nil)), nil
}
// buildSignString 计算签名字符串
func buildSignString(header map[string]string, url, method string) string {
var sb []string
sb = append(sb, strings.ToUpper(method))
sb = append(sb, "\n")
if header != nil {
if _, ok := header["Accept"]; ok {
sb = append(sb, header["Accept"])
sb = append(sb, "\n")
}
if _, ok := header["Content-MD5"]; ok {
sb = append(sb, header["Content-MD5"])
sb = append(sb, "\n")
}
if _, ok := header["Content-Type"]; ok {
sb = append(sb, header["Content-Type"])
sb = append(sb, "\n")
}
if _, ok := header["Date"]; ok {
sb = append(sb, header["Date"])
sb = append(sb, "\n")
}
}
sb = append(sb, buildSignHeader(header))
sb = append(sb, url)
return strings.Join(sb, "")
}
// buildSignHeader 计算签名头
func buildSignHeader(header map[string]string) string {
var sortedDicHeader map[string]string
sortedDicHeader = header
var sslice []string
for key, _ := range sortedDicHeader {
sslice = append(sslice, key)
}
sort.Strings(sslice)
var sbSignHeader []string
var sb []string
//在将key输出
for _, k := range sslice {
if strings.Contains(strings.ReplaceAll(k, " ", ""), "x-ca-") {
sb = append(sb, k+":")
if sortedDicHeader[k] != "" {
sb = append(sb, sortedDicHeader[k])
}
sb = append(sb, "\n")
if len(sbSignHeader) > 0 {
sbSignHeader = append(sbSignHeader, ",")
}
sbSignHeader = append(sbSignHeader, k)
}
}
header["x-ca-signature-headers"] = strings.Join(sbSignHeader, "")
return strings.Join(sb, "")
}
func MustJson(i interface{}) []byte {
if d, err := json.Marshal(i); err == nil {
return d
} else {
panic(err)
}
}
func MustJsonString(i interface{}) string {
return string(MustJson(i))
}
func MustString(value interface{}) string {
if value == nil {
return ""
}
return fmt.Sprintf("%v", value)
}
func Md5(str string) string {
h := md5.New()
h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))
}