• WCF 之UserName身份验证全记录


    本篇不是介绍WCF的基础知识,而专门讨论基于UserName的身份验证方式。

    关于WCF的基础知识,如果有不清楚的,请参考下面的链接

    http://msdn.microsoft.com/zh-cn/library/ms735119.aspx

    我现在用一个实录的方式,介绍一下UserName的身份验证

    1. 准备一个证书。这个证书将用来做消息的加密。

    我们可以通过SDK工具makecert创建一个测试证书,如下图

    makecert -r -pe -n "CN=WCFCert" -ss My -sky exchange

    image

    创建成功之后,我们可以在证书管理器中看到我们的证书

    image

    image

    2. 创建WCF服务库

    image

    修改名称,点击“确定”后创建的项目已经包含了一个简单的接口和服务

    image image image

    3. 测试该服务

    通过VS2008提供的工具,我们可以很方便地进行服务的测试工作。方法是:直接按F5

    image

    双击“GetData”

    image

    在“值”中输入一个数值,点击“调用”

    image

    点击“确定”后,在测试客户端的右下部分,会看到有关的响应

    image

    测试结果表示该服务是工作正常的。

    4.创建一个客户端来使用该服务

    我们通过创建一个Windows Forms程序来作为客户端。

    image

    项目创建好之后,我们需要为该项目添加一个服务引用

    image

    点击“添加服务引用”

    image

    点击“发现”按钮

    image

    点击“确定”按钮

    image

    5. 编写代码访问该服务

    private void btGetData_Click(object sender, EventArgs e)
    {
        TestService.Service1Client proxy = new Client.TestService.Service1Client();
        MessageBox.Show(proxy.GetData(2000));
    }

     

    6. 将客户端程序设置为启动项目,按F5调试

    image

    7. 现在的服务能正常工作了,但没有做任何的身份验证。这不能满足我们的需求。我们首先从服务端下手,进行设置

    image

    选择中WCFServiceLib中的app.config文件,然后右键菜单中点击“编辑WCF配置”

    image

    我们可以看到Service1这个服务,会有两个EndPoint(终结点)。其中第一个是标准的请求的终结点,而第二个(mex)是基于元数据的发现。

    我们点击第一个终结点(wsHttpBinding)下面的Binding configuration右边的 “单击可创建”

    image

    如果有兴趣,可以逐一了解每个属性。我们这里就不一一介绍了。因为此篇blog的目的是解决安全性问题

    点击窗口顶部的“安全性”

    image

    我们修改两个选项如下。即:在消息级别使用基于UserName的身份验证,而在传输级别不使用验证

    image

    接下来,我们还要配置服务行为。通过依次展开“高级”=》“服务行为”=》WCFServiceLib.Service1Behavier。我们能看到如下的界面

    image

    点击“添加”按钮

    image

    选择“serviceCredentials”,点击“添加”

    image

    双击“serviceCredentials”

    image

    这个窗口中主要要设置的是UserNamePasswordValidationMode。这里有三个选择,如下图所示

    image

    • Windows :基于windows的用户名和密码
    • MembershipProvider :基于成员管理提供程序
    • Custom : 自定义的身份验证提供程序

    我们先用Windows验证方式。

    image 

    我们还需要设置服务端证书的信息,如下

    image

    设置完之后,我们选择“文件”=》“保存”后,回到Visual Studio中的服务项目中的app.config

    <system.serviceModel>
       <bindings>
         <wsHttpBinding>
           <binding name="NewBinding0">
             <security>
               <transport clientCredentialType="None" />
               <message clientCredentialType="UserName" />
             </security>
           </binding>
         </wsHttpBinding>

       </bindings>
       <services>
         <service behaviorConfiguration="WCFServiceLib.Service1Behavior"
           name="WCFServiceLib.Service1">
           <endpoint address="" binding="wsHttpBinding" bindingConfiguration="NewBinding0"
             contract="WCFServiceLib.IService1">
             <identity>
               <dns value="localhost" />
             </identity>
           </endpoint>
           <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
           <host>
             <baseAddresses>
               <add baseAddress="http://localhost:8731/Design_Time_Addresses/WCFServiceLib/Service1/" />
             </baseAddresses>
           </host>
         </service>
       </services>
       <behaviors>
         <serviceBehaviors>
           <behavior name="WCFServiceLib.Service1Behavior">
             <serviceMetadata httpGetEnabled="true" />
             <serviceDebug includeExceptionDetailInFaults="false" />
             <serviceCredentials>
               <serviceCertificate findValue="WCFCert" storeLocation="CurrentUser"
                 x509FindType="FindBySubjectName" />
               <userNameAuthentication cacheLogonTokens="false" />

             </serviceCredentials>
           </behavior>
         </serviceBehaviors>
       </behaviors>
    </system.serviceModel>

    8. 完成服务端的配置后,我们先直接运行客户端程序。看看会发生什么情况

    image

    我们收到了一个异常消息。很显然,因为服务端已经启用了更加严格的安全性,客户端也需要有相应的设置才行

    9. 对客户端进行配置

    image

    我们发现这个终结点有一个相应的配置。接下来对其进行查看,确定MessageClientCredentialType也是Windows

    image

    接下来,我们还需要定义终结点行为

    image

    点击“新建终结点行为配置”

    image

    点击“添加”

    image

    选择“clientCredentials”.依次展开clientCredentials=>serviceCertificate=>defaultcertificate,并进行如下的设置。这里的证书需要与服务器端匹配,因为它将对消息进行加密。

    image

    选择“身份验证”

    image

    【注意】一定要把CertificateValidationMode设置为None。因为我们现在使用的是测试证书

    然后,回到终结点中,将终结点与行为进行关联。

    image

    并且,在“标识”页面进行如下的设置

    image

    完成如上的配置后,保存,退出该工具。

    <system.serviceModel>
        <behaviors>
            <endpointBehaviors>
                <behavior name="NewBehavior">
                    <clientCredentials>
                        <serviceCertificate>
                            <defaultCertificate findValue="WCFCert" x509FindType="FindBySubjectName" />
                            <authentication certificateValidationMode="None" />
                        </serviceCertificate>
                    </clientCredentials>

                </behavior>
            </endpointBehaviors>
        </behaviors>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IService1" 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="UserName" negotiateServiceCredential="true"
                            algorithmSuite="Default" establishSecurityContext="true" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8731/Design_Time_Addresses/WCFServiceLib/Service1/"
                behaviorConfiguration="NewBehavior" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IService1" contract="TestService.IService1"
                name="WSHttpBinding_IService1">
                <identity>
                    <certificateReference storeLocation="CurrentUser" x509FindType="FindBySubjectName"
                        findValue="WCFCert" />
                </identity>
            </endpoint>

        </client>
    </system.serviceModel>

    9. 修改客户端代码,在调用服务之前设置客户端的凭据

    image

    我们很高兴地看到,这样做了之后,就可以看到结果了

    image

    10. 进一步的扩展。

    上面的过程我们实现了对于WCF服务,使用基于windows的username验证的方式。但如果我们想更加有灵活性.首先看我们能不能使用自定义的代码来进行验证呢?

    11. 实现自定义的身份验证器

    image

    我们在服务项目中添加一个新的类

    同时,我们还需要添加两个引用

    image

    然后,编写该类型

    image

    12. 在服务器端指定使用该验证器

    image

    13. 客户端掉用调试

    【注意】客户端无需任何更改。我们还是像下面这样提供用户名和密码

    image

    因为这个用户名和密码是正确的,所以能正确返回。

    反之,如果我们修改一下密码,例如改成password1,则会发生一个异常

    image

    这样就实现了自定义的身份验证工作。

    14. 最后,其实我们还可以做得更加简单一些。就是不编写专门的用户密码验证器,而是直接使用ASP.NET 2.0新增加的所谓MemberShip的功能。(关于该功能,以及其配套的数据库,你可能需要参考其他的资料,这里不做介绍)

    我们首先在服务端配置文件中,添加如下的设置

      <connectionStrings>
      <add name="SqlServices" connectionString="server=(local);database=aspnetdb;integrated security=true"/>
    </connectionStrings>
    <system.web>
      <compilation debug="true" />
        <membership defaultProvider="SqlProvider">
        <providers>
          <clear />
          <add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="SqlServices" applicationName="demosite" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" requiresUniqueEmail="true" passwordFormat="Hashed" />
        </providers>
      </membership>
    </system.web>

    然后,继续配置服务的配置文件

    image

    同样,保存好配置后,客户端亦无须任何修改。直接调试一下看看

    image

    我们在数据库中有一个用户叫wcf,它的密码就是pass@word

    所以,通过如下的客户端代码就可以成功实现验证

    image

  • 相关阅读:
    45套精美的 ( Android, iPhone, iPad ) 手机界面设计素材和线框图设计工具
    JAVA基础01
    这是我的第一个博客
    string(更新)
    KMP
    标准C++中的string类的用法总结
    coj 数学作业(300)
    异或的性质及运用
    substr在oracle和mysql中的应用和区别
    非空校验在oracle和mysql中的用法
  • 原文地址:https://www.cnblogs.com/xuanqust/p/1738859.html
Copyright © 2020-2023  润新知