【问题标题】:WCF Authentication NT Challenge responseWCF 身份验证 NT 质询响应
【发布时间】:2011-03-29 05:36:47
【问题描述】:

当基本和/或 Windows 身份验证打开且匿名身份验证关闭时,如何让我的控制台应用与 IIS 托管的 WCF 服务连接?

该网站是内部网站,不需要严格的安全措施。没有域控制器。但是,我需要关闭匿名访问。

我已经搜索了几天并尝试了许多方法,包括使用自托管证书和覆盖证书验证、覆盖 UserNameValidator 和使用 client.ClientCredentials.Windows.ClientCredentials.UserName 或 client.ClientCredentials.UserName.UserName。这些都没有奏效。

如果有人愿意查看并运行代码并帮助我通过身份验证运行示例,那将是一件好事。

我冒昧地上传了一个沙盒解决方案,其中包含 HostWebSite、ClientConsole 和 API 项目。

我在我的 Windows Live SkyDrive 上托管了 zip 文件:WCF_Authentication.zip

一些小的设置步骤。

  1. 我添加到hosts文件127.0.0.1 hostwebsite.local

  2. 我在 IIS 中添加了一个网站
    -- 位置:HostWebSite project root,
    -- 绑定:hostwebsite.local
    -- 应用程序池:Classic 4.0 app pool。

  3. 应用安全Everyone 对 HostWebSite 项目目录的读取权限。

  4. 验证可以看到服务http://hostwebsite.local/services/EchoService.svc

  5. 验证控制台回显 hello world。

  6. 然后通过 IIS/身份验证关闭匿名并打开基本和/或 Windows 身份验证。

谢谢

为了读者的方便,我在这里包含了代码 sn-ps
项目:API

namespace API.Contract
{
    [ServiceContract]
    public interface IEcho
    {
        [OperationContract]
        string SendEcho(string message);
    }
}
namespace API.Proxy
{
    public class EchoProxy : IEcho
    {
        public string SendEcho(string message)
        {
            return string.Concat("You said: ", message);
        }
    }
}
namespace API.Service
{
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public class EchoService : System.ServiceModel.ClientBase<IEcho>, IEcho
    {

        public EchoService()
        {
        }

        public EchoService(string endpointConfigurationName) :
            base(endpointConfigurationName)
        {
        }

        public EchoService(string endpointConfigurationName, string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public EchoService(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public EchoService(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            base(binding, remoteAddress)
        {
        }

        public string SendEcho(string message)
        {
            return base.Channel.SendEcho(message);
        }
    }
}

项目:客户端控制台

static void Main(string[] args)
{
    EchoService client = new EchoService("WSHttpBinding_IEcho");

    try
    {
        Console.WriteLine(client.SendEcho("Hello World"));
        client.Close(); // i tried putting this in the finally block but the client would close in an errored state it said.
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    finally
    {

    }


    Console.WriteLine("Press any key to exit.");
    Console.ReadKey();
}

客户端配置

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IEcho" closeTimeout="00:01:00" openTimeout="00:01:00"
                receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
                transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                allowCookies="false">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <reliableSession ordered="true" inactivityTimeout="00:10:00"
                    enabled="false" />
                <security mode="Message">
                    <transport clientCredentialType="Windows" proxyCredentialType="None"
                        realm="" />
                    <message clientCredentialType="Windows" negotiateServiceCredential="true"
                        algorithmSuite="Default" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://hostwebsite.local/Services/EchoService.svc/services/EchoService.svc"
            binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IEcho"
            contract="API.Contract.IEcho" name="WSHttpBinding_IEcho">
            <identity>
                <servicePrincipalName value="host/mikev-ws" />
            </identity>
        </endpoint>
    </client>
</system.serviceModel>

项目:HostWebSite

<system.serviceModel>
    <!-- SERVER -->
    <behaviors>
        <serviceBehaviors>
            <behavior name="MyServiceTypeBehaviors">
                <serviceMetadata httpGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <services>
        <service name="API.Proxy.EchoProxy" behaviorConfiguration="MyServiceTypeBehaviors">
            <endpoint address="/services/EchoService.svc" binding="wsHttpBinding" contract="API.Contract.IEcho" />
            <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
        </service>
    </services>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>

</system.serviceModel>

【问题讨论】:

    标签: c# wcf wcf-binding wcf-security wcf-client


    【解决方案1】:

    您真的在关注消息级别的安全性吗?根据您的描述,您似乎需要传输级别的安全性(来自 IIS)。为此,您必须正确获取客户端配置文件。例如,

    <binding ...
       ...
       <security mode="TransportCredentialOnly">
           <transport clientCredentialType="windows" proxyCredentialType="None" realm="" />
    ...
    

    这将确保集成的 windows 身份验证 - 将使用当前运行客户端的 windows 用户进行身份验证。对于 NTLM/BASIC 身份验证,您需要从代码中提供用户名/密码 - 例如,

    <binding ...
           ...
           <security mode="TransportCredentialOnly">
               <transport clientCredentialType="Ntlm" proxyCredentialType="None" realm="" />
    

    在代码中,

    EchoService client = new EchoService("WSHttpBinding_IEcho");
    client.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential(userName, pwd);
    

    编辑:

    要使用 http 协议进行基本身份验证,您还必须在服务器端进行配置。例如,

    <system.serviceModel>
        <!-- SERVER -->
        <bindings>
            <basicHttpBinding>
                <binding name="NewBinding">
                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Basic" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        ...
        <services>
            <service name="API.Proxy.EchoProxy" ...
               <endpoint binding="basicHttpBinding" bindingConfiguration="NewBinding" contract="API.Contract.IEcho" />
          ...
    

    请参阅this article 了解更多信息。顺便说一句,您可能需要考虑 HTTPS 方案,因为基本身份验证以纯文本形式传输密码。

    【讨论】:

    • @VinayC:您好,感谢您的帮助。我已经尝试了你的两个建议。我不得不将绑定更改为 basicHttpBinding;那是对的吗?我收到的第一次配置更改的错误消息是The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Basic realm="hostwebsite.local"'.。配置更改和身份验证代码的第二条错误消息与我提到的第一个错误消息相同,只是将 Negotiate 替换为 Ntlm。谢谢
    • @Valamas,要使第一次配置更改生效,您必须在 IIS 上允许集成/Windows 身份验证。在这里,在客户端计算机上登录的用户的凭据将提供给服务器 - 如果此用户在服务器上未被识别,这将不起作用。要使用基本身份验证方案,您需要将 clientCredentialType 更改为基本,设置领域值,在代码中,您必须设置 ClientCredentials.UserName(设置用户和密码)。
    • @VinayC:我遵循基本身份验证路径。在 IIS 中仅启用基本身份验证。我遵循了您的最后陈述,包括我设置为空的领域。在 IIS 中,在基本身份验证下,领域和域字段也是空的。浏览到服务页面返回错误(http://hostwebsite.local/Services/EchoService.svc):Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.....(续)
    • 如果您希望查看当前配置和代码更改。 Here is a second zip.
    • @Valamas,应用程序 - 通常基本身份验证应该与 https 一起使用。因此,要与 http 一起使用,我相信您需要配置服务器端绑定,并且我已经编辑了答案以显示该部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    相关资源
    最近更新 更多