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、关闭如下“开启非法登录锁定”设置(可选)
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值