简体   繁体   English

使用WCF和自托管的Windows身份验证

[英]Windows Authentication using WCF and Self Hosting

I've developed a very simple host and client which I wanted to use to test whether it would be possible for a WCF client to pass the logged on windows' user's credentials to the host service without requiring the user to re-enter their credentials or setup security. 我已经开发了一个非常简单的主机和客户端,我想用它来测试WCF客户端是否可以将登录Windows的用户凭据传递给主机服务,而无需用户重新输入凭据或设置安全性。

My host config looks like this: 我的主机配置如下所示:

<configuration>
  <system.serviceModel>
    <services>
      <service name="WCFTest.CalculatorService" behaviorConfiguration="WCFTest.CalculatorBehavior">
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8000/WCFTest/CalculatorService/" />
            <add baseAddress = "net.tcp://localhost:9000/WCFTest/CalculatorService/" />
          </baseAddresses>
        </host>
        <endpoint address ="basicHttpEP" binding="basicHttpBinding" contract="WCFTest.ICalculatorService" bindingConfiguration="basicHttpBindingConfig"/>
        <endpoint address ="netTcpEP" binding="netTcpBinding" contract="WCFTest.ICalculatorService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name="basicHttpBindingConfig">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="WCFTest.CalculatorBehavior">          
          <serviceAuthorization impersonateCallerForAllOperations="false"  principalPermissionMode="UseWindowsGroups" />
          <serviceCredentials >
            <windowsAuthentication allowAnonymousLogons="false" includeWindowsGroups="true" />
          </serviceCredentials>
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

My client config looks like this: 我的客户端配置如下所示:

<configuration>
    <configSections>
        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="WCFClient.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_ICalculatorService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                    useDefaultWebProxy="true">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="UserName" algorithmSuite="Default" />
                    </security>
                </binding>
            </basicHttpBinding>
            <netTcpBinding>
                <binding name="NetTcpBinding_ICalculatorService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
                    hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                    maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                    maxReceivedMessageSize="65536">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Transport">
                        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="http://ldndwm286380:8000/WCFTest/CalculatorService/basicHttpEP"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICalculatorService"
                contract="CalcService.ICalculatorService" name="BasicHttpBinding_ICalculatorService" />
            <endpoint address="net.tcp://ldndwm286380:9000/WCFTest/CalculatorService/netTcpEP"
                binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculatorService"
                contract="CalcService.ICalculatorService" name="NetTcpBinding_ICalculatorService">
            </endpoint>
        </client>
    </system.serviceModel>
    <userSettings>
        <WCFClient.Settings1>
            <setting name="Setting" serializeAs="String">
                <value>True</value>
            </setting>
        </WCFClient.Settings1>
    </userSettings>
</configuration>

My client code is: 我的客户代码是:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press enter to start");
        Console.ReadLine();

        CalcService.ICalculatorService httpCalcService = new CalcService.CalculatorServiceClient("BasicHttpBinding_ICalculatorService");
        Console.WriteLine(httpCalcService.AddValues(new int[] { 1, 2, 3 }).Value);
        Console.ReadLine();

        CalcService.ICalculatorService TcpCalcService = new CalcService.CalculatorServiceClient("NetTcpBinding_ICalculatorService");
        Console.WriteLine(httpCalcService.AddValues(new int[] { 5, 10, 15 }).Value);
        Console.ReadLine();
    }
}

This works fine if I run the client on my PC. 如果我在PC上运行客户端,这将很好地工作。 If I run the client on a colleague's PC I get this exception stack on the client: 如果我在同事的PC上运行客户端,则会在客户端上获得此异常堆栈:

Unhandled Exception: System.ServiceModel.Security.MessageSecurityException: The HTTP request is unauthorized with client authentication scheme 'Negotiate'. 未处理的异常:System.ServiceModel.Security.MessageSecurityException:使用客户端身份验证方案“协商”对HTTP请求进行了未授权的处理。 The authentication header received from the server was 'Negotiate oX0we6ADCgEBonQEcm BwBgkqhkiG9xIBAgIDAH5hMF+gAwIBBaEDAgEepBEYDzIwMTAwMzExMTAzNjAzWqUFAgMEDFimAwIBKakYGxZJTlRSQU5FVC5CQVJDQVBJTlQuQ09NqhowGK ADAgEBoREwDxsNTERORFdNMjg2MzgwJA=='. 从服务器收到的身份验证标头是'Nootiate oX0we6ADCgEBonQEcm BwBgkqhkiG9xIBAgIDAH5hMF + gAwIBBaEDAgEepBEYDzIwMTAwMzExMTAzNjAzWqUFAgMEDFimAwIBKakGgXJJL1QQQ5K ---> System.Net.WebException: The remote server returned an error: (401) Unauthoriz ed. ---> System.Net.WebException:远程服务器返回错误:(401)未授权。 ---> System.ComponentModel.Win32Exception: The target principal name is incorrect at System.Net.NTAuthentication.GetOutgoingBlob(Byte[] incomingBlob, Boolean throwOnError, SecurityStatus& statusCode) ---> System.ComponentModel.Win32Exception:目标主体名称在System.Net.NTAuthentication.GetOutgoingBlob(Byte [] entryBlob,Boolean throwOnError,SecurityStatus&statusCode)处不正确

at System.Net.NTAuthentication.GetOutgoingBlob(String incomingBlob) at System.Net.NegotiateClient.DoAuthenticate(String challenge, WebRequest webRequest, ICredentials credentials, Boole an preAuthenticate) at System.Net.NegotiateClient.Authenticate(String challenge, WebRequest webRequest, ICredentials credentials) at System.Net.AuthenticationManager.Authenticate(String challenge, WebRequest request, ICredentials credentials) at System.Net.AuthenticationState.AttemptAuthenticate(HttpWebRequest httpWebRequest, ICredentials authInfo) at System.Net.HttpWebRequest.CheckResubmitForAuth() at System.Net.HttpWebRequest.CheckResubmit(Exception& e) --- End of inner exception stack trace --- at System.Net.HttpWebRequest.GetResponse() at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeou t) --- End of inner exception stack trace --- 在System.Net.NegotiateClient.DoAuthenticate(字符串质询,WebRequest WebRequest,ICredentials凭据,Boole的preAuthenticate)中的System.Net.NTAuthentication.GetOutgoingBlob(String传入的Blob)处在System.Net.NegotiateClient.Authenticate(字符串质询,WebRequest WebRequest,ICredentials中) System.Net.AuthenticationManager.Authenticate(字符串质询,WebRequest请求,ICredentials凭据)处System.Net.AuthenticationState.AttemptAuthenticate(HttpWebRequest httpWebRequest,ICredentials authInfo)处System.Net.HttpWebRequest.CheckResubmitForAuth()。 HttpWebRequest.CheckResubmit(Exception&e)-内部异常堆栈跟踪的结尾--在System.Net.HttpWebRequest.GetResponse()在System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)- -内部异常堆栈跟踪结束-

Any help appreciated, 任何帮助表示赞赏,

Thanks, 谢谢,

Nick 缺口

Within the configuration for your client, you'll need to add an additional element within your 'endpoint' element to specify the principal that the service is running under. 在客户端的配置中,您需要在'endpoint'元素内添加一个附加元素,以指定运行该服务的主体。 Here is an example: 这是一个例子:

<identity>
      <servicePrincipalName value="user@mydomain.com" />
</identity>

This should allow for proper authentication to occur when establishing a channel between your client and host. 在客户端和主机之间建立通道时,这应允许进行正确的身份验证。 If the service is being run under a different account, you will need to adjust the value accordingly (ie if it is running as a windows service using the system account, it would be similar to 'host/mymachine.mydomain.com'). 如果该服务在其他帐户下运行,则需要相应地调整该值(即,如果使用系统帐户作为Windows服务运行,则类似于“ host / mymachine.mydomain.com”)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM