[索引页]
[×××] 


化零为整WCF(17) - 安全(Security)


作者:webabcd


介绍
WCF(Windows Communication Foundation) - 安全(Security):本文以用户名和密码做验证,通过X.509证书做加密为例


示例
1、证书

setup.bat
makecert -sr LocalMachine -ss My -a sha1 -n CN=Webabcd -sky exchange -pe
certmgr -add -r LocalMachine -s My -c -n Webabcd -s TrustedPeople
 
2、服务
IHello.cs
化零为整WCF(17) - 安全(Security)_休闲using System;
化零为整WCF(17) - 安全(Security)_休闲using System.Collections.Generic;
化零为整WCF(17) - 安全(Security)_休闲using System.Linq;
化零为整WCF(17) - 安全(Security)_休闲using System.Text;
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲using System.ServiceModel;
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲namespace WCF.ServiceLib.Security
化零为整WCF(17) - 安全(Security)_休闲{
化零为整WCF(17) - 安全(Security)_休闲        /// <summary>
化零为整WCF(17) - 安全(Security)_休闲        /// IHello接口
化零为整WCF(17) - 安全(Security)_休闲        /// </summary>
化零为整WCF(17) - 安全(Security)_休闲        [ServiceContract]
化零为整WCF(17) - 安全(Security)_休闲        public interface IHello
化零为整WCF(17) - 安全(Security)_休闲        {
化零为整WCF(17) - 安全(Security)_休闲                /// <summary>
化零为整WCF(17) - 安全(Security)_休闲                /// 打招呼方法
化零为整WCF(17) - 安全(Security)_休闲                /// </summary>
化零为整WCF(17) - 安全(Security)_休闲                /// <param name="name">人名</param>
化零为整WCF(17) - 安全(Security)_休闲                /// <returns></returns>
化零为整WCF(17) - 安全(Security)_休闲                [OperationContract]
化零为整WCF(17) - 安全(Security)_休闲                string SayHello(string name);
化零为整WCF(17) - 安全(Security)_休闲        }
化零为整WCF(17) - 安全(Security)_休闲}
 
Hello.cs
化零为整WCF(17) - 安全(Security)_休闲using System;
化零为整WCF(17) - 安全(Security)_休闲using System.Collections.Generic;
化零为整WCF(17) - 安全(Security)_休闲using System.Linq;
化零为整WCF(17) - 安全(Security)_休闲using System.Text;
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲using System.ServiceModel;
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲namespace WCF.ServiceLib.Security
化零为整WCF(17) - 安全(Security)_休闲{
化零为整WCF(17) - 安全(Security)_休闲        /// <summary>
化零为整WCF(17) - 安全(Security)_休闲        /// Hello类
化零为整WCF(17) - 安全(Security)_休闲        /// </summary>
化零为整WCF(17) - 安全(Security)_休闲        public class Hello : IHello
化零为整WCF(17) - 安全(Security)_休闲        {
化零为整WCF(17) - 安全(Security)_休闲                /// <summary>
化零为整WCF(17) - 安全(Security)_休闲                /// 打招呼方法
化零为整WCF(17) - 安全(Security)_休闲                /// </summary>
化零为整WCF(17) - 安全(Security)_休闲                /// <param name="name">人名</param>
化零为整WCF(17) - 安全(Security)_休闲                /// <returns></returns>
化零为整WCF(17) - 安全(Security)_休闲                public string SayHello(string name)
化零为整WCF(17) - 安全(Security)_休闲                {
化零为整WCF(17) - 安全(Security)_休闲                        return "Hello: " + name;
化零为整WCF(17) - 安全(Security)_休闲                }
化零为整WCF(17) - 安全(Security)_休闲        }
化零为整WCF(17) - 安全(Security)_休闲}
 
CustomNamePasswordValidator.cs
化零为整WCF(17) - 安全(Security)_休闲using System;
化零为整WCF(17) - 安全(Security)_休闲using System.Collections.Generic;
化零为整WCF(17) - 安全(Security)_休闲using System.Linq;
化零为整WCF(17) - 安全(Security)_休闲using System.Text;
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲using System.ServiceModel;
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲namespace WCF.ServiceLib.Security
化零为整WCF(17) - 安全(Security)_休闲{
化零为整WCF(17) - 安全(Security)_休闲        /// <summary>
化零为整WCF(17) - 安全(Security)_休闲        /// 自定义的用户名/密码验证类
化零为整WCF(17) - 安全(Security)_休闲        /// </summary>
化零为整WCF(17) - 安全(Security)_休闲        public class CustomNamePasswordValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
化零为整WCF(17) - 安全(Security)_休闲        {
化零为整WCF(17) - 安全(Security)_休闲                /// <summary>
化零为整WCF(17) - 安全(Security)_休闲                /// 验证指定的用户名和密码
化零为整WCF(17) - 安全(Security)_休闲                /// </summary>
化零为整WCF(17) - 安全(Security)_休闲                /// <param name="userName">要验证的用户名</param>
化零为整WCF(17) - 安全(Security)_休闲                /// <param name="password">要验证的密码</param>
化零为整WCF(17) - 安全(Security)_休闲                public override void Validate(string userName, string password)
化零为整WCF(17) - 安全(Security)_休闲                {
化零为整WCF(17) - 安全(Security)_休闲                        if (!(userName == "webabcd" && password == "webabcd"))
化零为整WCF(17) - 安全(Security)_休闲                        {
化零为整WCF(17) - 安全(Security)_休闲                                throw new FaultException("用户名或密码不正确");
化零为整WCF(17) - 安全(Security)_休闲                        }
化零为整WCF(17) - 安全(Security)_休闲                }
化零为整WCF(17) - 安全(Security)_休闲        }
化零为整WCF(17) - 安全(Security)_休闲}
 
 
3、宿主
Hello.svc
<%@ ServiceHost Language="C#" Debug="true" Service="WCF.ServiceLib.Security.Hello" %>
 
Web.config
<?xml version="1.0"?>
<configuration>
        <system.serviceModel>
                <services>
                        <!--name - 提供服务的类名-->
                        <!--behaviorConfiguration - 指定相关的行为配置-->
                        <service name="WCF.ServiceLib.Security.Hello" behaviorConfiguration="SecurityBehavior">
                                <!--address - 服务地址-->
                                <!--binding - 通信方式-->
                                <!--contract - 服务契约-->
                                <endpoint address="" binding="wsHttpBinding" contract="WCF.ServiceLib.Security.IHello" bindingConfiguration="SecurityBindingConfiguration"    />
                        </service>
                </services>
                <behaviors>
                        <serviceBehaviors>
                                <behavior name="SecurityBehavior">
                                        <!--httpGetEnabled - 指示是否发布服务元数据以便使用 HTTP/GET 请求进行检索,如果发布 WSDL,则为 true,否则为 false,默认值为 false-->
                                        <serviceMetadata httpGetEnabled="true" />
                                        <serviceDebug includeExceptionDetailInFaults="true"/>
                                        <serviceCredentials>
                                                <!--userNamePasswordValidationMode - 以用户名/密码模式来进行验证的方法-->
                                                <!--UserNamePasswordValidationMode.Windows - 用户名映射到 Windows 用户-->
                                                <!--UserNamePasswordValidationMode.MembershipProvider - 提供基于已配置的 MembershipProvider 的密码验证-->
                                                <!--UserNamePasswordValidationMode.Custom - 基于已配置的自定义 UsernamePasswordValidator 的自定义身份验证-->
                                                <!--customUserNamePasswordValidatorType - 所使用的自定义用户名密码验证程序的类型-->
                                                <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCF.ServiceLib.Security.CustomNamePasswordValidator, WCF.ServiceLib" />
                                                <!--findValue - 指定要在 X.509 证书存储区中搜索的值-->
                                                <!--storeLocation - 指定客户端可用于验证服务器证书的证书存储区位置(LocalMachine - 分配给本地计算机的 X.509 证书存储区;CurrentUser - 当前用户使用的 X.509 证书存储区)-->
                                                <!--storeName - 要打开的 X.509 证书存储区的名称(参看:StoreName枚举。AddressBook, AuthRoot, CertificateAuthority, Disallowed, My, Root, TrustedPeople, TrustedPublisher)-->
                                                <!--x509FindType - 要执行的 X.509 搜索的类型(参看:X509FindType枚举)-->
                                                <serviceCertificate findValue="Webabcd" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
                                        </serviceCredentials>
                                </behavior>
                        </serviceBehaviors>
                </behaviors>
                <bindings>
                        <wsHttpBinding>
                                <binding name="SecurityBindingConfiguration">
                                        <security>
                                                <!--clientCredentialType - 客户端用以进行身份验证的凭据的类型,默认值 UserName -->
                                                <!--BasicHttpMessageCredentialType.UserName - 使用用户名凭据对客户端进行身份验证-->
                                                <!--BasicHttpMessageCredentialType.Certificate - 使用证书对客户端进行身份验证-->
                                                <message clientCredentialType="UserName" />
                                        </security>
                                </binding>
                        </wsHttpBinding>
                </bindings>
        </system.serviceModel>
</configuration>
 
 
4、客户端
Hello.aspx
<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Hello.aspx.cs"
        Inherits="Sample_Security" Title="安全(Security)" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
        <p>
                以用户名和密码做验证,通过X.509证书做加密为例
        </p>
        <p>
                <asp:Label ID="lblMsg" runat="server" />
        </p>
        <p>
                用户名:<asp:TextBox ID="txtUserName" runat="server" Text="webabcd" />
                     
                密码:<asp:TextBox ID="txtPassword" runat="server" Text="webabcd" />
        </p>
        <p>
                <asp:TextBox ID="txtName" runat="server" Text="webabcd" />
                 
                <asp:Button ID="btnSayHello" runat="server" Text="Hello" OnClick="btnSayHello_Click" />
        </p>
</asp:Content>
 
Hello.aspx.cs
化零为整WCF(17) - 安全(Security)_休闲using System;
化零为整WCF(17) - 安全(Security)_休闲using System.Collections;
化零为整WCF(17) - 安全(Security)_休闲using System.Configuration;
化零为整WCF(17) - 安全(Security)_休闲using System.Data;
化零为整WCF(17) - 安全(Security)_休闲using System.Linq;
化零为整WCF(17) - 安全(Security)_休闲using System.Web;
化零为整WCF(17) - 安全(Security)_休闲using System.Web.Security;
化零为整WCF(17) - 安全(Security)_休闲using System.Web.UI;
化零为整WCF(17) - 安全(Security)_休闲using System.Web.UI.HtmlControls;
化零为整WCF(17) - 安全(Security)_休闲using System.Web.UI.WebControls;
化零为整WCF(17) - 安全(Security)_休闲using System.Web.UI.WebControls.WebParts;
化零为整WCF(17) - 安全(Security)_休闲using System.Xml.Linq;
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲public partial class Sample_Security : System.Web.UI.Page
化零为整WCF(17) - 安全(Security)_休闲{
化零为整WCF(17) - 安全(Security)_休闲        protected void Page_Load(object sender, EventArgs e)
化零为整WCF(17) - 安全(Security)_休闲        {
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲        }
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲        protected void btnSayHello_Click(object sender, EventArgs e)
化零为整WCF(17) - 安全(Security)_休闲        {
化零为整WCF(17) - 安全(Security)_休闲                using (var proxy = new SecuritySvc.HelloClient())
化零为整WCF(17) - 安全(Security)_休闲                {
化零为整WCF(17) - 安全(Security)_休闲                        try
化零为整WCF(17) - 安全(Security)_休闲                        {
化零为整WCF(17) - 安全(Security)_休闲                                // proxy.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.PeerTrust;
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲                                proxy.ClientCredentials.UserName.UserName = txtUserName.Text;
化零为整WCF(17) - 安全(Security)_休闲                                proxy.ClientCredentials.UserName.Password = txtPassword.Text;
化零为整WCF(17) - 安全(Security)_休闲
化零为整WCF(17) - 安全(Security)_休闲                                lblMsg.Text = proxy.SayHello(txtName.Text);
化零为整WCF(17) - 安全(Security)_休闲                        }
化零为整WCF(17) - 安全(Security)_休闲                        catch (TimeoutException ex)
化零为整WCF(17) - 安全(Security)_休闲                        {
化零为整WCF(17) - 安全(Security)_休闲                                lblMsg.Text = ex.ToString();
化零为整WCF(17) - 安全(Security)_休闲                                proxy.Abort();
化零为整WCF(17) - 安全(Security)_休闲                        }
化零为整WCF(17) - 安全(Security)_休闲                        catch (Exception ex)
化零为整WCF(17) - 安全(Security)_休闲                        {
化零为整WCF(17) - 安全(Security)_休闲                                lblMsg.Text = ex.ToString();
化零为整WCF(17) - 安全(Security)_休闲                                proxy.Abort();
化零为整WCF(17) - 安全(Security)_休闲                        }
化零为整WCF(17) - 安全(Security)_休闲                }
化零为整WCF(17) - 安全(Security)_休闲        }
化零为整WCF(17) - 安全(Security)_休闲}
 
Web.config
<?xml version="1.0"?>
<configuration>
        <system.serviceModel>
                <client>
                        <!--address - 服务地址-->
                        <!--binding - 通信方式-->
                        <!--contract - 服务契约-->
                        <!--bindingConfiguration - 指定相关的绑定配置-->
                        <!--behaviorConfiguration - 指定相关的行为配置-->
                        <endpoint address="http://localhost:3502/ServiceHost/Security/Hello.svc"
                                binding="wsHttpBinding"
                                contract="SecuritySvc.IHello"
                                bindingConfiguration="HelloBindingConfiguration"
                                behaviorConfiguration="HelloBehaviorConfiguration">
                                <identity>
                                        <!--encodedValue - 此证书编码的值。公钥,用于加密用户名和密码。测试时,请根据实际情况修改此值-->
                                        <certificate encodedValue="AwAAAAEAAAAUAAAAwMJESjc9Bbgeh9hIrrdrlMz0nfEgAAAAAQAAALMBAAAwggGvMIIBXaADAgECAhBC+dqPonX5pEwDPMLbdE9MMAkGBSsOAwIdBQAwFjEUMBIGA1UEAxMLUm9vdCBBZ2VuY3kwHhcNMDgwNzE1MDczODIwWhcNMzkxMjMxMjM1OTU5WjASMRAwDgYDVQQDEwdXZWJhYmNkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwfrBPcMSOWVJmDnn+EFfCOslH0OqC5s67C6e19XQ7oMh6a9hP9Os4hefNoGxcdPK3orV4y4pHn0VOvHgaeAJqreRjmgmyb+h2BDB7nkmhchBxQZUx4jSX0GUrqECZm9uUMrNq8vx7NtaEuEMs5q50KPaxrv6PwuKLssNnb3WC1wIDAQABo0swSTBHBgNVHQEEQDA+gBAS5AktBh0dTwCNYSHcFmRjoRgwFjEUMBIGA1UEAxMLUm9vdCBBZ2VuY3mCEAY3bACqAGSKEc+41KpcNfQwCQYFKw4DAh0FAANBAE/6rAQhU3X1RficEHPEeUAX7HQQXZDYByQt0QqE7C8PaViQWlWU+Sp8u9Oy3ce4DSg3wgQLL/DIknG7FMIiGRE=" />
                                </identity>
                        </endpoint>
                </client>
                <bindings>
                        <wsHttpBinding>
                                <binding name="HelloBindingConfiguration">
                                        <security>
                                                <!--clientCredentialType - 客户端用以进行身份验证的凭据的类型,默认值 UserName -->
                                                <!--BasicHttpMessageCredentialType.UserName - 使用用户名凭据对客户端进行身份验证-->
                                                <!--BasicHttpMessageCredentialType.Certificate - 使用证书对客户端进行身份验证-->
                                                <message clientCredentialType="UserName" />
                                        </security>
                                </binding>
                        </wsHttpBinding>
                </bindings>
                <behaviors>
                        <endpointBehaviors>
                                <behavior name="HelloBehaviorConfiguration">
                                        <clientCredentials>
                                                <serviceCertificate>
                                                        <!--authentication - 证书验证模式 -->
                                                        <!--X509CertificateValidationMode.None - 不使用证书验证-->
                                                        <!--X509CertificateValidationMode.PeerTrust - 如果证书位于被信任的人的存储区中,则有效-->
                                                        <!--X509CertificateValidationMode.ChainTrust - 如果该链在受信任的根存储区生成证书颁发机构,则证书有效-->
                                                        <!--X509CertificateValidationMode.PeerOrChainTrust -如果证书位于被信任的人的存储区或该链在受信任的根存储区生成证书颁发机构,则证书有效 -->
                                                        <!--X509CertificateValidationMode.Custom -用户必须插入自定义 X509CertificateValidator 以验证证书 -->
                                                        <authentication certificateValidationMode="PeerTrust" />
                                                </serviceCertificate>
                                        </clientCredentials>
                                </behavior>
                        </endpointBehaviors>
                </behaviors>
        </system.serviceModel>
</configuration>
 
 

运行结果:
单击"btnSayHello"按钮,显示"Hello: webabcd"。经过加密的用户名和密码放在SOAP头中传输。


OK
[×××]