我正在尝试从ONVIF IP摄像机获取运动检测器事件。我可以获取订阅的主题地址,但是当我尝试从中提取消息时,会收到错误消息:
Error 401 fault detected[no subcode]
"HTTP/1.1 401 Unauthorized"
Detail: <!DOCTYPE html>
<html><head><title>Document Error: Unauthorized</title></head>
<body><h2>Access Error: 401 -- Unauthorized</h2>
<p>Authentication Error: Access Denied! Authorization required.</p>
</body>
</html>
我创建了多个代理,例如DeviceProxy,EventsProxy,PullPointProxy,并为每个请求添加了安全标头和时间戳,但只有PullPointProxy无法授权它们。
void COnvifMotionDetectorWorker::AddSecurity(soap* pProxy, const bool& bAddWsse)
{
if(bAddWsse)
{
soap_wsse_add_Security(pProxy);
}
if(SOAP_OK != soap_wsse_add_UsernameTokenDigest(pProxy, "Auth", m_sUsername.c_str(), m_sPassword.c_str()))
{
m_Logger.LogMessage(
NLogger2::ePriorityLevelError,
std::string("Error adding username token"),
"COnvifMotionDetectorWorker::AddSecurity()",
std::string("DeviceId #") + m_sDeviceId);
}
if(SOAP_OK != soap_wsse_add_Timestamp(pProxy, "Time", 10))
{
m_Logger.LogMessage(
NLogger2::ePriorityLevelError,
std::string("Error adding timestamp"),
"COnvifMotionDetectorWorker::AddSecurity()",
std::string("DeviceId #") + m_sDeviceId);
}
}
void COnvifMotionDetectorWorker::Body()
{
DeviceBindingProxy DeviceProxy;
AddSecurity(&DeviceProxy, true);
DeviceProxy.soap_endpoint = m_sDeviceUrl.c_str();
_tds__GetCapabilities deviceCapabilities;
deviceCapabilities.Category.push_back(tt__CapabilityCategory__All);
_tds__GetCapabilitiesResponse deviceCapabilitiesResponse;
if(SOAP_OK == DeviceProxy.GetCapabilities(&deviceCapabilities, deviceCapabilitiesResponse))
{
if(deviceCapabilitiesResponse.Capabilities->Events != nullptr)
{
m_Logger.LogMessage(
NLogger2::ePriorityLevelInfo,
std::string("Device has event capabilities"),
"COnvifMotionDetectorWorker::BeforeBody()",
std::string("DeviceId #") + m_sDeviceId);
PullPointSubscriptionBindingProxy EventsProxy(
deviceCapabilitiesResponse.Capabilities->Events->XAddr.c_str());
EventsProxy.soap_endpoint = deviceCapabilitiesResponse.Capabilities->Events->XAddr.c_str();
AddSecurity(&EventsProxy, true);
_tev__GetEventProperties gep;
_tev__GetEventPropertiesResponse gepr;
if (EventsProxy.GetEventProperties(&gep, gepr) == SOAP_OK)
{
PrintOnvifParameter("Event: TopicNamespaceLocation");
for (size_t i = 0; i < gepr.TopicNamespaceLocation.size(); i++)
{
PrintOnvifParameter("", gepr.TopicNamespaceLocation.at(i).c_str());
}
PrintOnvifParameter("Event: fixedTopicSet", gepr.wsnt__FixedTopicSet ? "Yes" : "No");
PrintOnvifParameter("Event: Topics:");
if (gepr.wstop__TopicSet != NULL && gepr.wstop__TopicSet->documentation != NULL && gepr.wstop__TopicSet->documentation->__mixed != NULL)
{
PrintOnvifParameter("", gepr.wstop__TopicSet->documentation->__mixed);
}
else
{
PrintOnvifParameter("", "None");
}
PrintOnvifParameter("Event: MessageContentFilterDialect");
for (size_t i = 0; i < gepr.MessageContentFilterDialect.size(); i++)
{
PrintOnvifParameter("", gepr.MessageContentFilterDialect.at(i).c_str());
}
PrintOnvifParameter("Event: MessageContentSchemaLocation");
for (size_t i = 0; i < gepr.MessageContentSchemaLocation.size(); i++)
{
PrintOnvifParameter("", gepr.MessageContentSchemaLocation.at(i).c_str());
}
PrintOnvifParameter("Event: ProducerPropertiesFilterDialect");
for (size_t i = 0; i < gepr.ProducerPropertiesFilterDialect.size(); i++)
{
PrintOnvifParameter("", gepr.ProducerPropertiesFilterDialect.at(i).c_str());
}
PrintOnvifParameter("Event: wsnt__TopicExpressionDialect");
for (size_t i = 0; i < gepr.wsnt__TopicExpressionDialect.size(); i++)
{
PrintOnvifParameter("", gepr.wsnt__TopicExpressionDialect.at(i).c_str());
}
}
else
{
EventsProxy.soap_stream_fault(std::cerr);
PrintOnvifParameter("Error getting event profiles");
}
PrintOnvifParameter("Event: Creating pull point:");
AddSecurity(&EventsProxy, true);
_tev__CreatePullPointSubscription cpps;
_tev__CreatePullPointSubscriptionResponse cppr;
std::string termtime = "PT60S";
cpps.InitialTerminationTime = &termtime;
if (EventsProxy.CreatePullPointSubscription(&cpps, cppr) == SOAP_OK)
{
PrintOnvifParameter("Event: pull point subscription created:");
PrintOnvifParameter("termination time", std::to_string(cppr.wsnt__TerminationTime));
PrintOnvifParameter("SubscriptionReference.Address", cppr.SubscriptionReference.Address);
if (cppr.SubscriptionReference.__anyAttribute != nullptr)
{
PrintOnvifParameter("__anyAttribute", cppr.SubscriptionReference.__anyAttribute);
}
PrintOnvifParameter("SubscriptionReference.__size", std::to_string(cppr.SubscriptionReference.__size));
for (int i = 0; i < cppr.SubscriptionReference.__size; i++)
{
PrintOnvifParameter("__any", cppr.SubscriptionReference.__any[i]);
}
if (cppr.SubscriptionReference.Metadata != nullptr)
{
if (cppr.SubscriptionReference.Metadata->__anyAttribute != nullptr)
{
PrintOnvifParameter("Metadata->__anyAttribute",
cppr.SubscriptionReference.ReferenceParameters->__anyAttribute);
}
for (int i = 0; i < cppr.SubscriptionReference.Metadata->__size; i++)
{
PrintOnvifParameter("MetaData__any",
cppr.SubscriptionReference.Metadata->__any[i]);
}
}
if (cppr.SubscriptionReference.ReferenceParameters != nullptr)
{
if (cppr.SubscriptionReference.ReferenceParameters->__anyAttribute != nullptr)
{
PrintOnvifParameter("ReferenceParameter->__anyAttribute",
cppr.SubscriptionReference.ReferenceParameters->__anyAttribute);
}
PrintOnvifParameter("SubscriptionReference.ReferenceParameters->__size",
std::to_string(cppr.SubscriptionReference.ReferenceParameters->__size));
for (int i = 0; i < cppr.SubscriptionReference.ReferenceParameters->__size; i++)
{
PrintOnvifParameter("ReferenceParameter",
cppr.SubscriptionReference.ReferenceParameters->__any[i]);
}
}
// Set up proxy to read from subscription reference
std::string sSubscriptionAddress = cppr.SubscriptionReference.Address;
PullPointSubscriptionBindingProxy PullPointProxy(sSubscriptionAddress.c_str());
AddSecurity(&PullPointProxy, true);
while(!m_bExit)
{
_tev__PullMessages PullMessages;
PullMessages.Timeout = "PT10S";
PullMessages.MessageLimit = 100;
_tev__PullMessagesResponse PullMessagesResponse;
int nRetCode = SOAP_OK;
if ((nRetCode = PullPointProxy.PullMessages(&PullMessages, PullMessagesResponse)) == SOAP_OK)
{
for (auto msg : PullMessagesResponse.wsnt__NotificationMessage)
{
ProcessOnvifMessage(msg->Message.__any);
}
}
else
{
PullPointProxy.soap_stream_fault(std::cerr);
m_Logger.LogMessage(
NLogger2::ePriorityLevelError,
std::string("PullPointProxy.PullMessages() error code is ") + std::to_string(nRetCode),
"COnvifMotionDetectorWorker::Body()",
std::string("DeviceId #") + m_sDeviceId);
}
// Wait for nothing
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
}
else
{
m_Logger.LogMessage(
NLogger2::ePriorityLevelError,
std::string("No device events capabilities"),
"COnvifMotionDetectorWorker::BeforeBody()",
std::string("DeviceId #") + m_sDeviceId);
}
}
else
{
m_Logger.LogMessage(
NLogger2::ePriorityLevelError,
std::string("Error getting device capabilities"),
"COnvifMotionDetectorWorker::BeforeBody()",
std::string("DeviceId #") + m_sDeviceId);
}
// Wait for nothing before ending
std::this_thread::sleep_for(std::chrono::seconds(1));
}
正在运行的程序的日志为:
PrintOnvifParameter(): Event: TopicNamespaceLocation -
PrintOnvifParameter(): - http://www.onvif.org/onvif/ver10/topics/topicns.xml
PrintOnvifParameter(): Event: fixedTopicSet - Yes
PrintOnvifParameter(): Event: Topics: -
PrintOnvifParameter(): - None
PrintOnvifParameter(): Event: MessageContentFilterDialect -
PrintOnvifParameter(): - http://www.onvif.org/ver10/tev/messageContentFilter/ItemFilter
PrintOnvifParameter(): Event: MessageContentSchemaLocation -
PrintOnvifParameter(): - http://www.onvif.org/onvif/ver10/schema/onvif.xsd
PrintOnvifParameter(): Event: ProducerPropertiesFilterDialect -
PrintOnvifParameter(): Event: wsnt__TopicExpressionDialect -
PrintOnvifParameter(): - http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet
PrintOnvifParameter(): - http://docs.oasis-open.org/wsn/t-1/TopicExpression/Concrete
PrintOnvifParameter(): Event: Creating pull point: -
PrintOnvifParameter(): Event: pull point subscription created: -
PrintOnvifParameter(): termination time - 1557833982
PrintOnvifParameter(): SubscriptionReference.Address - http://192.168.1.36/onvif/Events/PullSubManager_2019-05-14T11:38:42Z_1
PrintOnvifParameter(): __anyAttribute -
PrintOnvifParameter(): SubscriptionReference.__size - 0
请帮助您理解为什么只有PullMessages返回错误以及正确验证需要哪些特定参数?
答案 0 :(得分:0)
可以向谁考虑...
问题出在WS-Addressing标头中: https://www.w3.org/Submission/ws-addressing/ https://www.genivia.com/doc/wsdd/html/wsa_0.html
我将其添加到我的PullMessage请求中,并得到了摄像头的响应。
代码应为:
// Set up proxy to read from subscription reference
std::string sSubscriptionAddress = cppr.SubscriptionReference.Address;
PullPointSubscriptionBindingProxy PullPointProxy(sSubscriptionAddress.c_str());
AddSecurity(&PullPointProxy);
soap_register_plugin(&PullPointProxy, soap_wsa);
while(!m_bExit)
{
AddSecurity(&PullPointProxy, false);
if (SOAP_OK != soap_wsa_request(&PullPointProxy,
nullptr,
sSubscriptionAddress.c_str(),
"http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesRequest") ||
(SOAP_OK != soap_wsa_add_ReplyTo(&PullPointProxy,
"http://www.w3.org/2005/08/addressing/anonymous"))
)
{
PullPointProxy.soap_stream_fault(std::cerr);
m_Logger.LogMessage(
NLogger2::ePriorityLevelError,
std::string("soap_wsa_request error"),
"COnvifMotionDetectorWorker::Body()",
std::string("DeviceId #") + m_sDeviceId);
}
_tev__PullMessages PullMessages;
PullMessages.Timeout = "PT1M";
PullMessages.MessageLimit = 1024;
_tev__PullMessagesResponse PullMessagesResponse;
int nRetCode = SOAP_OK;
if ((nRetCode = PullPointProxy.PullMessages(&PullMessages, PullMessagesResponse)) == SOAP_OK)
{
for (auto msg : PullMessagesResponse.wsnt__NotificationMessage)
{
ProcessOnvifMessage(msg->Message.__any);
}
}
else
{
PullPointProxy.soap_stream_fault(std::cerr);
m_Logger.LogMessage(
NLogger2::ePriorityLevelError,
std::string("PullPointProxy.PullMessages() error code is ") + std::to_string(nRetCode),
"COnvifMotionDetectorWorker::Body()",
std::string("DeviceId #") + m_sDeviceId);
}
// Wait for nothing
std::this_thread::sleep_for(std::chrono::seconds(1));
}