> 技术文档 > ESP32通过onvif获取的HTTP读海康摄像头截图,arduino代码实现digest认证

ESP32通过onvif获取的HTTP读海康摄像头截图,arduino代码实现digest认证

        ESP32开发,所以不能用海康SDK,之前用QT开发时也不想用SDK,发现有这种通过HTTP直接获取最新截图的方式,直接一个QNetworkRequest,不要太简单。URL是这样的:http://user:password@192.168.1.64/onvif-http/snapshot?Profile_2

        本来还用onvif去获取URL,后发现是固定的,也不用每次去获取XML了。

话不多说,贴代码

String md5(String str)
{
  MD5Builder md;
  md.begin();
  md.add(str);
  md.calculate();
  return md.toString();
}
String extractParam(String& authHeader, String param) {
    int start = authHeader.indexOf(param + \"=\\\"\") + param.length() + 2;
    int end = authHeader.indexOf(\"\\\"\", start);
    return authHeader.substring(start, end);
}

int digestAuthRequest(HTTPClient &http) {
  const char* keys[] = {\"WWW-Authenticate\"};
  http.collectHeaders(keys, 1);
  int httpCode = http.GET();
  if(httpCode == HTTP_CODE_UNAUTHORIZED) {
    String authHeader = http.header(\"WWW-Authenticate\");
    // 解析realm, nonce等参数
    String realm = extractParam(authHeader, \"realm\");
    String nonce = extractParam(authHeader, \"nonce\");
    //String opaque = extractParam(authHeader, \"opaque\");

    // 计算响应值
    String ha1 = md5(\"admin:\" + realm + \":password\");//我这里user是admin直接写死了
    String ha2 = md5(\"GET:/onvif-http/snapshot?Profile_2\");
    String response = md5(ha1 + \":\" + nonce + \":\" + ha2);
        
    // 构造Authorization头部
    String authHeaderValue = \"Digest username=\\\"admin\\\", realm=\\\"\" + realm + 
                            \"\\\", nonce=\\\"\" + nonce + \"\\\", uri=\\\"/onvif-http/snapshot?Profile_2\\\", \" +
                            \"response=\\\"\" + response + \"\\\"\";
    
    // 发送认证请求
    http.addHeader(\"Authorization\", authHeaderValue);
    httpCode = http.GET();
  }
  return httpCode;
}

注意点:网上有代码缺少collectHeaders过程,导致http.header(...)得不到内容!

以下是使用的代码:
#define USE_SERIAL Serial

    //从http获取
    HTTPClient http;

    USE_SERIAL.print(\"[HTTP] begin...\\n\");
    // configure traged server and url

    //http.begin(\"http://user:password@192.168.1.64/onvif-http/snapshot?Profile_2\");//这种默认是basic认证,新海康摄像头用不了
    http.begin(\"http://192.168.1.64/onvif-http/snapshot?Profile_2\");

    USE_SERIAL.print(\"[HTTP] GET...\\n\");
    // start connection and send HTTP header
    //int httpCode = http.GET();//这是直接get,会得到401,要求认证
    int httpCode = digestAuthRequest(http);//这里会判断401,则去digest认证

    // httpCode will be negative on error
    if (httpCode > 0) {
      // HTTP header has been send and Server response header has been handled
      USE_SERIAL.printf(\"[HTTP] GET... code: %d,%d\\n\", httpCode,httpCode2);

      // file found at server
      if (httpCode == HTTP_CODE_OK) {
        // create buffer for read
        uint8_t buff[1024] = {0};

        int len = http.getSize();
        USE_SERIAL.println(len);
        // get tcp stream
        NetworkClient *stream = http.getStreamPtr();
        // read all data from server
        while (http.connected() && len > 0) {
          if(http.connected() && len>0) {
            // get available data size
            size_t size = stream->available();

            if (size) {
              int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));

              // write it to tcp
              tcp.write(buff, c);//我这里是转发给服务器,再保存为png文件

              if (len > 0) {
                len -= c;
              }
            }
            delay(1);
          }
        }
      }
    }
使用的代码很平常,arduino的HTTPClient例子很多,我就替换了http.GET()这函数,在返回401的时候加上了认证。其实更应该完善HTTPClient这个库更合理,我找到头文件中有
  void setAuthorization(const char *user, const char *password);
  void setAuthorization(const char *auth);
  void setAuthorizationType(const char *authType);

可惜setAuthorizationType这函数只是会把认证类型直接填上,后面的加密方式还是直接按base64,有这么段代码:

if (_base64Authorization.length()) {
    _base64Authorization.replace(\"\\n\", \"\");
    header += F(\"Authorization: \");
    header += _authorizationType;
    header += \" \";
    header += _base64Authorization;
    header += \"\\r\\n\";
  }

不深究了,自己的需求是实现了。

附新摄像头配置:
1、配置->高级配置->集成协议中勾选 启用onvif
2、请你为onvif协议设置用户名和密码(admin,password,管理员),这是onvif协议认证时候需要的
3、关闭如下“开启非法登录锁定”设置(可选)