如何使用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