dinggela 发表于 2018-6-13 08:01:04

WCF简单教程(8) 安全

  第八篇:WCF安全
  WCF提供了非常丰富的加密机制与审核机制,以保证对外提供的服务安全可靠。本文是简单教程,所以只挑其中的一小部分来聊聊。
  先来看看最简单的Windows认证。
  所谓Windows认证,是指客户端访问时,要提供服务端认可的Windows用户身份。
  1、服务端
  安全配置主要体现在App.config中:


[*]<?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?>
[*]<configuration>
[*]<system.serviceModel>
[*]    <services>
[*]      <service name=&quot;Server.DataProvider&quot;>
[*]      <!-- 本例中使用netTcpBinding,注意指定了一个名为tcpBinding的设置,见下文 -->
[*]      <endpoint address=&quot;&quot; binding=&quot;netTcpBinding&quot; contract=&quot;Server.IData&quot; bindingConfiguration=&quot;tcpBinding&quot; />
[*]      <host>
[*]          <baseAddresses>
[*]            <add baseAddress=&quot;net.tcp://localhost:8081/wcf&quot; />
[*]          </baseAddresses>
[*]      </host>
[*]      </service>
[*]    </services>
[*]
[*]    <!--客户端的身份认证是设置在bindings节中的-->
[*]    <bindings>
[*]      <!--注意此节要与前面的binding匹配,表示为netTcpBinding方式的绑定进行配置-->
[*]      <netTcpBinding>
[*]      <!--定义一个名为tcpBinding的设置,就是前面endpoint中用到的-->
[*]      <binding name=&quot;tcpBinding&quot;>
[*]          <!--使用Message方式的加密,至于它与Transport方式的区别,可先忽略,后面再讲-->
[*]          <security mode=&quot;Message&quot;>
[*]            <!--指定客户端认证使用Windows方式-->
[*]            <message clientCredentialType=&quot;Windows&quot; />
[*]          </security>
[*]      </binding>
[*]      </netTcpBinding>
[*]    </bindings>
[*]</system.serviceModel>
[*]</configuration>

  契约实现类我们修改一下,方便看到调用者的身份:


[*]using System;
[*]using System.ServiceModel;
[*]
[*]namespace Server
[*]{
[*]   
[*]    public class DataProvider : IData
[*]    {
[*]      public string SayHello()
[*]      {
[*]            //WindowsIdentity即代表访问者的身份标识
[*]            return string.Format(&quot;Hello {0}&quot;, OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name);
[*]      }
[*]    }
[*]}

  
2、客户端
  客户端要对应调整App.config:


[*]<?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?>
[*]<configuration>
[*]<system.serviceModel>
[*]    <client>
[*]      <!--定义endpoint时指定使用特定的配置,另外这个IP是一会儿运行服务端的机器的IP-->
[*]      <endpoint binding=&quot;netTcpBinding&quot; contract=&quot;Server.IData&quot; address=&quot;net.tcp://192.168.90.90:8081/wcf&quot; name=&quot;DataProvider&quot; bindingConfiguration=&quot;tcp&quot; />
[*]    </client>
[*]    <!--客户端与服务端的bindings节设置一致-->
[*]    <bindings>
[*]      <netTcpBinding>
[*]      <binding name=&quot;tcp&quot;>
[*]          <security mode=&quot;Message&quot;>
[*]            <message clientCredentialType=&quot;Windows&quot; />
[*]          </security>
[*]      </binding>
[*]      </netTcpBinding>
[*]    </bindings>
[*]</system.serviceModel>
[*]</configuration>

  
然后是代码,要指定访问时客户端使用的用户名密码:


[*]using System;
[*]using System.ServiceModel;
[*]using System.ServiceModel.Channels;
[*]
[*]namespace Client
[*]{
[*]    class Program
[*]    {
[*]      static void Main(string[] args)
[*]      {
[*]            //创建一个ChannelFactory,指定使用名为DataProvider的配置
[*]            var factory = new ChannelFactory<Server.IData>(&quot;DataProvider&quot;);
[*]
[*]            //指定用户名、密码,这个Test是服务端Windows上的一个普通帐户,如果加入了域,还要指定ClientCredential.Domain
[*]            factory.Credentials.Windows.ClientCredential.UserName= &quot;Test&quot;;
[*]            factory.Credentials.Windows.ClientCredential.Password = &quot;test&quot;;
[*]
[*]            //创建Channel,并调用SayHello方法
[*]            var proxy = factory.CreateChannel();
[*]            Console.WriteLine(proxy.SayHello());
[*]            ((IChannel)proxy).Close();
[*]      }
[*]    }
[*]}

  其中的指定的用户名与密码是服务端存在的一个Windows用户。
  
OK,在两台机器上分别运行服务端和客户端,能够正常完成调用,输出“Hello Test-PC\Test”,这个Test-PC\Test就是我们调用时传递的用户身份,注意是“机器名\用户名”的形式,如果是AD环境,那么就是“域\用户名”的形式。
  如果给定一个错误的用户名密码,则调用时会收到Exception:


[*]未处理的异常:System.ServiceModel.Security.SecurityNegotiationException: 调用方未由服务进行身份验证。 ---> System.ServiceModel.FaultException: 无法满足对安全令牌的请求,因为身份验证失败。
[*]   在 System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
[*]   在 System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)

  是一个身份验证失败的异常。
  
用Windows帐户来做验证,其实是个挺麻烦的事情,只有较少的系统是这么做的,我们还是希望能用更通用的用户名密码来进行身份验证,下一篇我们就来看看如何做。
页: [1]
查看完整版本: WCF简单教程(8) 安全