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

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

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

我创建像官方ONVIF文档(35-36页)在SOAP请求。 http://www.onvif.org/Portals/0/documents/WhitePapers/ONVIF_WG-APG-Application_Programmer's_Guide.pdf。 “admin”和“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();

这是创建和CreateSoapRequest()返回我的SOAP请求:

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的东西,发现设置安全凭证非常花哨。 首先我要说确保您的日期格式是这样的:

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]);

希望这有助于!

回答:

我一直在处理这个很长一段时间,这里是我用来获取所有验证的东西功能:

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);

}

我希望这hepls。

以上是 如何使用SOAP操作和HttpClient向授权的网络摄像机发送ONVIF请求 的全部内容, 来源链接: utcz.com/qa/264376.html

回到顶部