1

这个问题已经在这里的几个主题中讨论过,但我找不到适合我的答案。

我想做的是通过 Onvif 接口使用 IP 摄像机。我已经从 Onvif 主页中可用的 WSDL 文件生成了 Web 服务,并按照此处的建议添加了自定义 SOAP 身份验证代码,并且我能够检索设备功能等。

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

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 的第一次体验,到目前为止,我已经从互联网上找到的示例中完成了所有工作,但是对于这个特定问题,我还没有找到任何东西。

4

2 回答 2

3

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

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)身份验证级别上工作。

于 2014-02-28T13:18:13.683 回答
0

我在另一个答案中详细介绍了 HTTP 摘要的工作原理。

请记住PRE_AUTH,根据核心规范的§5.12.1,只有 class 的功能需要身份验证。

您应该调用除 PRE_AUTH 之外的任何类的函数,而无需任何表单身份验证。如果你得到了,HTTP 401那么你必须使用 HTTP digset,否则你必须使用 WS-UsernameToken。

您不能直接使用 HTTP 摘要,因为您至少需要设备向您发送 HTTP 摘要的挑战。

于 2014-02-28T07:36:13.063 回答