本文介绍了具有SOAP级别身份验证和HTTP身份验证的Onvif SOAP请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题已在此处的多个主题中进行了讨论,但我找不到适合我的答案.

This question has been discussed in several topics here but I could not find the answer for me.

我想做的是通过Onvif界面使用IP摄像机.我已经从Onvif主页上的WSDL文件生成了Web服务,并按照建议,并且我能够检索设备功能等.

What I'm trying to do is use an IP camera through the Onvif interface. I've generated the web services from the WSDL files available in the Onvif homepage, and added the custom SOAP authentication code as suggested here, and I am able to retrieve the device capabilities etc. etc.

但是对于某些服务(例如PTZ控制),还需要HTTP身份验证.我的代码删除了ClientCredentials behaivor(是的,我想设置它们没有任何意义,但是我仍然留下这些行,希望HTTP传输会尝试使用它们):

But for some services, e.g, PTZ control, also HTTP authentication is needed. My code removes the ClientCredentials behaivor (so yeah, I guess setting them does not make any sense, but I still left those lines in hope that maybe the HTTP transport would try to use them):

HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
httpBindingElement.AuthenticationScheme = AuthenticationSchemes.Basic;
...
PTZClient ptzClient = new PTZClient(customBinding, endPointAddress);
ptzClient.Endpoint.Behaviors.Remove(typeof(System.ServiceModel.Description.ClientCredentials));
UsernameClientCredentials onvifCredentials = new UsernameClientCredentials(new UsernameInfo(_username, _password));
ptzClient.Endpoint.Behaviors.Add(onvifCredentials);
ptzClient.ClientCredentials.UserName.UserName = _username;
ptzClient.ClientCredentials.UserName.Password = _password;

当我查看Wireshark时,仍然看到生成了SOAP身份验证,但是未设置HTTP身份验证标头(嗯,由于我在这里有自定义的行为,我已经预料到了).因此,问题是,如果我以这种方式创建绑定,添加HTTP身份验证标头的最佳选择是什么?我可以只添加一个消息检查器吗,如果可以,是否可以添加任何示例?我必须创建其他传输绑定吗?我见过有人建议其他人使用BasicHttpBinding,然后在其上设置Security属性,但是在这种情况下,凭据会放在哪里,以及如何将BasicHttpBinding实例应用于绑定? WCF中是否有我可以连接到然后提供标头的HTTP 401代码触发的回调?这实际上是我第一次使用WCF,到目前为止,我已经从Internet上的示例中完成了所有工作,但是对于这个特定问题,我什么都找不到.

Still when I look at wireshark, i see that the SOAP authentication is generated but no HTTP authentication header is set (well, I already expected that since i have a custom behaivor here). So the question is, if I am creating the binding this way, what are my best options to add HTTP authentication headers? Can I just add a message inspector, and if so, any examples? Must I create a different transport binding? I've seen people advising others to use BasicHttpBinding and then setting the Security property on that, but where do the credentials go in that case and how do I apply the BasicHttpBinding instance to my binding? Are there any callbacks in the WCF that get triggered by the HTTP 401 code that i can hook up to and then provide the header? This is actually my first experience with WCF and so far I've done everything from examples found in the internet, but as for this particular issue I haven't been able to find anything.

推荐答案

如果有人感兴趣,这就是我的工作方式.我通过以下方式将BasicHttpBinding与客户端凭据结合在一起:

If anyone is interested this is how I got it working. I combined the BasicHttpBinding with the client credentials in a following way:

TransportSecurityBindingElement transportSecurity = new TransportSecurityBindingElement();
// UsernameCredentials is a class implementing WS-UsernameToken authentication
transportSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(new UsernameTokenParameters());
transportSecurity.AllowInsecureTransport = true;
transportSecurity.IncludeTimestamp = false;
TextMessageEncodingBindingElement messageEncoding = new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8);
HttpClientCredentialType[] credentialTypes = new HttpClientCredentialType[3] { HttpClientCredentialType.None, HttpClientCredentialType.Basic, HttpClientCredentialType.Digest };
...
foreach (HttpClientCredentialType credentialType in credentialTypes)
{
    BasicHttpBinding httpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
    httpBinding.Security.Transport.ClientCredentialType = credentialType;
    BindingElementCollection elements = new BindingElementCollection(new BindingElement[1]{messageEncoding});
    foreach(BindingElement element in httpBinding.CreateBindingElements())
    {
        if (element is TextMessageEncodingBindingElement)
            continue;
        elements.Add(element);
    }
    CustomBinding customBinding = new CustomBinding(elements);
    DeviceClient deviceClient = new DeviceClient(customBinding, endPointAddress);
    if (credentialType == HttpClientCredentialType.Basic)
    {
         // Set all credentials, not sure from which one WCF actually takes the value
         deviceClient.ClientCredentials.UserName.UserName = pair[0];
         deviceClient.ClientCredentials.UserName.Password = pair[1];
    }
    else if (credentialType == HttpClientCredentialType.Digest)
    {
        deviceClient.ClientCredentials.HttpDigest.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
        deviceClient.ClientCredentials.HttpDigest.ClientCredential.UserName = pair[0];
        deviceClient.ClientCredentials.HttpDigest.ClientCredential.Password = pair[1];
    }
}

这可以在我们不知道其身份验证模式的设备上有效地工作,并且可以在两种(HTTP/SOAP)身份验证级别上使用.

This works efficiently with a device for which we do not know the authentication mode and works on both (HTTP/SOAP) authentication level.

这篇关于具有SOAP级别身份验证和HTTP身份验证的Onvif SOAP请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-19 17:07