• 如何在WCF解决方案中使用WCS(windows cardspace)作为身份验证方式


    本文提供了一个引导步骤,讲解了如何在WCF解决方案中采用WCS作为身份验证方式。本文假设你已经清楚地了解了WCF的各项机制。

    第一部分:服务部分

    1. 服务契约

    using System.ServiceModel;
    
    namespace HelloService
    {
        [ServiceContract]
        public interface IHello
        {
            [OperationContract]
            string Say();
        }
    }
    2. 服务实现和宿主程序
    需要预先引用System.ServiceModel,System.IdentityModel
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using System.ServiceModel;
    using System.IdentityModel.Claims;
    using System.IdentityModel.Policy;
    
    namespace HelloService
    {
    
    
        class Hello : IHello
        {
    
            #region IHello 成员
    
            public string Say()
            {
                GetIdentity();
                return "Hello,World";
            }
    
            private void GetIdentity()
            {
                AuthorizationContext ctx =
    OperationContext.Current.ServiceSecurityContext.AuthorizationContext;
                foreach (ClaimSet claimSet in ctx.ClaimSets)
                {
                    foreach (Claim claim in claimSet)
                    {
                        Console.WriteLine();
                        Console.WriteLine("ClaimType: " + claim.ClaimType);
                        Console.WriteLine("Resource: " + claim.Resource);
                        Console.WriteLine("Right: " + claim.Right);
                    }
                }
                return;
            }
    
            #endregion
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                ServiceHost sh = new ServiceHost(typeof(Hello), new Uri("http://localhost:4123/helloService"));
                sh.Open();
                Console.WriteLine("Service listening...");
                Console.WriteLine("Press <Enter> to finish");
                Console.ReadLine();
                sh.Close(); // close the service
            }
        }
    }
    
    代码中的GetIdentity方法是我们自己写的,主要是为了解析Windows Cardspace传递过来的凭据信息。
     
    3. 服务配置
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service
          name="HelloService.Hello"
          behaviorConfiguration="helloServiceBehavior">
            <endpoint
            address="helloEndpoint"
            contract="HelloService.IHello"
            binding="wsFederationHttpBinding"
            bindingConfiguration="helloFederatedBinding">
    
              <identity>
                <certificateReference
                findValue="WCFTestCert"
                storeLocation="CurrentUser"
                storeName="My"
                x509FindType="FindBySubjectName" />
              </identity>
            </endpoint>
            <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
          </service>
        </services>
        <bindings>
          <wsHttpBinding>
            <binding name="helloBinding">
              <security mode="Message">
                <message clientCredentialType="IssuedToken" />
              </security>
            </binding>
          </wsHttpBinding>
    
          <wsFederationHttpBinding>
            <binding name="helloFederatedBinding" >
              <security mode="Message">
                <message
                algorithmSuite="Basic128"
                issuedTokenType="urn:oasis:names:tc:SAML:1.0:assertion"
                issuedKeyType="SymmetricKey">
                  <issuer address="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self"/>
                  <claimTypeRequirements>
                    <add claimType ="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"/>
                    <add claimType ="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"/>
                  </claimTypeRequirements>
                </message>
              </security>
            </binding>
          </wsFederationHttpBinding>
        </bindings>
        <behaviors>
          <serviceBehaviors>
            <behavior name="helloServiceBehavior">
              <serviceMetadata httpGetEnabled="true" />
    
              <serviceCredentials>
                <issuedTokenAuthentication allowUntrustedRsaIssuers="true" />
                <serviceCertificate
                findValue="WCFTestCert"
                storeLocation="CurrentUser"
                storeName="My"
                x509FindType="FindBySubjectName" />
              </serviceCredentials>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>
    在这里,我们指定了一个特殊的binding(wsFederationHttpBinding)这是专用于WCS的。并且我们声明了当前应用程序需要两部分信息,一个是emailaddress,一个是givename
    需要注意的是,我们需要在服务端设置证书,并且在endpoint对其进行引用,这是什么道理呢? 因为客户端也要对服务进行验证。
     
    第二部分:客户端部分
    1. 服务契约
    using System.ServiceModel;
    
    namespace HelloService
    {
        [ServiceContract]
        public interface IHello
        {
            [OperationContract]
            string Say();
        }
    }
    
    2. 客户端代码
     
    using System;
    
    using System.ServiceModel;
    
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Hit any key when service is ready");
                Console.ReadKey();
                ChannelFactory<HelloService.IHello> cnFactory =
                new ChannelFactory<HelloService.IHello>("helloClient");
                HelloService.IHello chn = cnFactory.CreateChannel();
                Console.WriteLine(chn.Say());
                // Clean up
                cnFactory.Close(); // close the client’s channel
                Console.WriteLine("Press <Enter> to finish");
                Console.ReadLine();
            }
        }
    }
    
    3. 客户端配置
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <client>
          <endpoint
          name="helloClient"
          address="http://localhost:4123/helloService/helloEndpoint"
          contract="HelloService.IHello"
          binding="wsFederationHttpBinding"
          bindingConfiguration="helloFederatedBinding"
          behaviorConfiguration="helloClientBehavior">
            <identity>
              <certificateReference
              findValue="WCFTestCert"
              storeLocation="CurrentUser"
              storeName="My"
              x509FindType="FindBySubjectName" />
            </identity>
          </endpoint>
        </client>
        <bindings>
          <wsHttpBinding>
            <binding name="helloBinding">
              <security mode="Message">
                <message clientCredentialType="IssuedToken" />
              </security>
            </binding>
          </wsHttpBinding>
    
          <wsFederationHttpBinding>
            <binding name="helloFederatedBinding" >
              <security mode="Message">
                <message
                algorithmSuite="Basic128"
                issuedTokenType="urn:oasis:names:tc:SAML:1.0:assertion"
                issuedKeyType="SymmetricKey">
                  <issuer address="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self"/>
                  <claimTypeRequirements>
                    <add claimType ="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"/>
                    <add claimType ="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"/>
                  </claimTypeRequirements>
                </message>
              </security>
            </binding>
          </wsFederationHttpBinding>
        </bindings>
        <behaviors>
          <endpointBehaviors>
            <behavior name="helloClientBehavior">
              <clientCredentials>
                <serviceCertificate>
                  <authentication
                  trustedStoreLocation="CurrentUser"
                  revocationMode="NoCheck"/>
                  <defaultCertificate
                  findValue="WCFTestCert"
                  storeLocation="CurrentUser"
                  storeName="My"
                  x509FindType="FindBySubjectName" />
                </serviceCertificate>
              </clientCredentials>
            </behavior>
          </endpointBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>

    也就是说,在客户端也是需要包含证书的。一般是把不包含私钥的证书在客户端安装。

     

    4. 运行效果

    服务端

    image

    客户端

    image

    [备注]因为是Session的隔离,所以选择卡片的界面是没有办法截图的。

    4. 为客户端实现异常处理

    添加System.IdentityModel.Selectors引用

    image

    using System;
    
    using System.ServiceModel;
    using System.IdentityModel.Selectors;
    
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Console.WriteLine("Hit any key when service is ready");
                    Console.ReadKey();
                    ChannelFactory<HelloService.IHello> cnFactory = new
                    ChannelFactory<HelloService.IHello>("helloClient");
                    HelloService.IHello chn = cnFactory.CreateChannel();
                    Console.WriteLine(chn.Say());
                    cnFactory.Close();
                }
                catch (UserCancellationException)
                {
                    Console.WriteLine("User cancelled");
                }
                catch (UntrustedRecipientException)
                {
                    Console.WriteLine("User does not trust the recipient");
                }
                catch (ServiceNotStartedException)
                {
                    Console.WriteLine("Cardspace service not started");
                }
                catch (CardSpaceException cse)
                {
                    Console.WriteLine("Generic Cardspace exception:" + cse.Message);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Other exceptions :" + e.Message);
                }
                finally
                {
                    Console.WriteLine("Press <Enter> to finish");
                    Console.ReadLine();
                }
            }
        }
    }
    
  • 相关阅读:
    FreeRTOS移植到Cortex-M3-M4
    码位颠倒C程序
    开平方与魔数0x5F3759DF:Quake III 开源代码
    MathJax: Web 页面显示数学公式
    Notepad++ NppExport: 让你在Microsoft word 中粘贴语法高亮代码
    [转]matlab 函数三种定义方式
    机器上的几种Eclipse
    自己开发CC3000模块
    Java中的线程的生命周期大体可分为5种状态
    srand和rand的用法和联系
  • 原文地址:https://www.cnblogs.com/chenxizhang/p/1675262.html
Copyright © 2020-2023  润新知