如何发送ONVIF请求与授权的网络摄像机,使用SOAP动作和HttpClient

本文关键字:SOAP 使用 HttpClient 摄像机 网络 ONVIF 何发送 请求 授权 | 更新日期: 2023-09-27 18:18:28

我正在做一个发现和控制本地网络摄像头的项目。我是一个c++程序员,所以我不擅长。net,但是这个项目我们是用c#写的,我遇到了一些问题。我使用DiscoveryClient来发现本地网络中的所有设备。接下来,我获得摄像机地址,创建HttpClient并尝试发送SOAP操作。ONVIF规格:http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl。一些操作(例如GetServiceCapabilities)返回响应,但是大多数操作返回这个错误:

<env:Body><env:Fault><env:Code><env:Value>env:Sender</env:Value>
<env:Subcode><env:Value>ter:NotAuthorized</env:Value>
</env:Subcode>
</env:Code>
<env:Reason><env:Text xml:lang="en">The action requested requires authorization and the sender is not authorized</env:Text>
</env:Reason>
</env:Fault>
</env:Body>

我正在创建SOAP请求,就像官方ONVIF文档(第35-36页)。http://www.onvif.org/Portals/0/documents/WhitePapers/ONVIF_WG-APG-Application_Programmer 's_Guide.pdf。"admin"answers"12345"-是我们测试网络摄像头的登录名和密码。

这是我的代码,我试图在下面发送请求:

HttpClient httpClient = new HttpClient();
var byteArray = Encoding.UTF8.GetBytes("admin:12345");
var request = requestStructure.CreateSoapRequest();
httpClient.DefaultRequestHeaders.Add("SOAPACTION", "'"" + requestStructure.actionNamespace + "#" + requestStructure.actionName + "'"");
httpClient.DefaultRequestHeaders.Add("Authorization", "Digest " + Convert.ToBase64String(byteArray));
var resp = await httpClient.PostAsync(requestedUri, new StringContent(request, UnicodeEncoding.UTF8));
var respString = await resp.Content.ReadAsStringAsync();

我的SOAP请求是由CreateSoapRequest()创建并返回的:

public string CreateSoapRequest()
{
    var nonce64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(this.nonce.ToString()));
    var date64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(this.dateCreated));
    var password64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(this.password));
    SHA1 sha = new SHA1CryptoServiceProvider();
    var passwordDigest = sha.ComputeHash(Encoding.UTF8.GetBytes(nonce64 + date64 + password64));
    password64 = Convert.ToBase64String(passwordDigest);
    this.requestBodyString =
                    "<soap:Envelope "
                       + "xmlns:soap='"http://schemas.xmlsoap.org/soap/envelope/'" "
                       + "soap:encodingStyle='"http://schemas.xmlsoap.org/soap/encoding/'">"
                       + "<soap:Header>"
                            + "<Security s:mustUnderstand='"1'" xmlns:w='"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'">"
                                + "<UsernameToken>"
                                    + "<Username>" + this.login + "</Username>"
                                    + "<Password Type='"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest'">" + password64 + "</Password>"
                                    + "<Nonce EncodingType='"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'">" + nonce64 + "</Nonce>"
                                    + "<Created xmlns='"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'">" + this.dateCreated + "</Created>"
                                + "</UsernameToken>"
                            + "</Security>"
                       + "</soap:Header>"
                       + "<soap:Body>"
                            + "<u:" + this.actionName + " "
                            + "xmlns:u='"" + this.actionNamespace + "'">"
                            + this.actionParameters
                            + "</u:" + this.actionName + ">"
                       + "</soap:Body>" +
                    "</soap:Envelope>'r'n'r'n";
    return this.requestBodyString;
}

谢谢你的帮助!

如何发送ONVIF请求与授权的网络摄像机,使用SOAP动作和HttpClient

我已经处理这个问题很长一段时间了,这里是我用来获取所有认证内容的函数:

    static void GetPasswordDigest()
    {
        //Get nonce
        Random rnd = new Random();
        Byte[] nonce_b = new Byte[16];
        rnd.NextBytes(nonce_b);
        nonce64 = Convert.ToBase64String(nonce_b);
        Console.WriteLine("Nonce: " + nonce64);
        //Get timestamp
        DateTime created = DateTime.Now;
        creationtime = created.ToString("yyyy-MM-ddTHH:mm:ssZ");
        Byte[] creationtime_b = Encoding.ASCII.GetBytes(creationtime);
        Console.WriteLine("Timestamp: " + creationtime);
        //Convert the plain password to bytes
        Byte[] password_b = Encoding.ASCII.GetBytes(ONVIFPassword);
        //Concatenate nonce_b + creationtime_b + password_b
        Byte[] concatenation_b = new byte[nonce_b.Length + creationtime_b.Length + password_b.Length];
        System.Buffer.BlockCopy(nonce_b, 0, concatenation_b, 0, nonce_b.Length);
        System.Buffer.BlockCopy(creationtime_b, 0, concatenation_b, nonce_b.Length, creationtime_b.Length);
        System.Buffer.BlockCopy(password_b, 0, concatenation_b, nonce_b.Length + creationtime_b.Length, password_b.Length);
        //Apply SHA1 on the concatenation
        SHA1 sha = new SHA1CryptoServiceProvider();
        Byte[] pdresult = sha.ComputeHash(concatenation_b);
        passworddigest = Convert.ToBase64String(pdresult);
        Console.WriteLine("Password digest: " + passworddigest);
    } 

我最近做了很多Onvif的事情,发现设置安全凭证非常繁琐。首先,我想说的是,确保你的日期格式如下:

 var now = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddThh:mm:ss.fffZ");

与我的唯一不同之处在于(它工作得很好),我在标题中多了一行:

string xml = string.Format(@"<?xml version='1.0' encoding='UTF-8'?>"+
                                   "<s:Envelope xmlns:s='http://www.w3.org/2003/05/soap-envelope'>" +
                                   "<s:Header>" +
                                   "<Security s:mustUnderstand='1' xmlns='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'>" +
                                   "<UsernameToken>" +
                                   "<Username>{0}</Username>" +
                                   "<Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest'>" +
                                   "{1}" +
                                   "</Password>" +
                                   "<Nonce EncodingType='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'>" +
                                   "{2}" +
                                   "</Nonce>" +
                                   "<Created xmlns='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>" +
                                   "{3}" +
                                   "</Created>" +
                                   "</UsernameToken>" +
                                   "</Security>" +
                                   "</s:Header>", user, credentials[0], b64Nonce, credentials[2]);

希望这对你有帮助!