WCF安全-账号与密码登陆

来源:互联网 发布:python settimeout 编辑:程序博客网 时间:2024/05/16 07:58

1、介绍

WCF支持多种认证技术,例如Windowns认证、X509证书、Issued Tokens、用户名密码认证等,在跨Windows域分布的系统中,用户名密码认证还是比较常用的,要实现用户名密码认证,就必须需要X509证书,为什么呢?因为我们需要X509证书这种非对称密钥技术来实现WCF在Message传递过程中的加密和解密,要不然用户名和密码就得在网络上明文传递!详细说明就是客户端把用户名和密码用公钥加密后传递给服务器端,服务器端再用自己的私钥来解密,然后传递给相应的验证程序来实现身份验证。

2、生成X509证书

当然,做个测试程序就没有必要去申请一个X509数字签名证书了,微软提供了一个makecert.exe的命令专门用来生成测试使用的X509证书的,那我们就来建立一个测试用的证书,在cmd下输入以下命令:

makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=MyServerCert -sky exchange –pe

这个命令的意思就是创建一个测试的X509证书,这个证书放在存储位置为'Localmachine'的'My'这个文件夹下,证书主题名字叫'MyServerCert'

3、服务端代码

3.1、WCF项目上添加引用'System.IdentityModel'

3.2、建立一个新的类文件并继承自'System.IdentityModel.Selectors.UserNamePasswordValidator',然后我们重写里面的'Validate'方法来实现用户名密码认证逻辑。

3.3、代码

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IdentityModel.Selectors;

using System.IdentityModel.Tokens;

 

namespace ServerWcfService.CustomValidators

{

public class MyCustomValidator : UserNamePasswordValidator

{

/// <summary>

/// Validates the user name and password combination.

/// </summary>

/// <param name="userName">The user name.</param>

/// <param name="password">The password.</param>

public override void Validate(string userName, string password)

{

// validate arguments

if (string.IsNullOrEmpty(userName))

throw new ArgumentNullException("userName");

if (string.IsNullOrEmpty(password))

throw new ArgumentNullException("password");

 

// check if the user is not xiaozhuang

if (userName != "xiaozhuang" || password != "123456")

throw new SecurityTokenException("用户名或者密码错误!");

}

}

}

3.4、WEB.CONFIG文件配置

<system.serviceModel>

        <bindings>

            <wsHttpBinding>

                <binding name="mySecureBinding">

                    <security mode="Message">

                        <message clientCredentialType="UserName"/>

                    </security>

                </binding>

            </wsHttpBinding>

        </bindings>

        <services>

            <service behaviorConfiguration="ServerWcfService.Services.MySimpleServiceBehavior"name="ServerWcfService.Services.MySimpleService">

                <endpoint address="" binding="wsHttpBinding"contract="ServerWcfService.ServiceContracts.IMySimpleService" bindingConfiguration="mySecureBinding">

                    <identity>

                        <dns value="MyServerCert"/>

                    </identity>

                </endpoint>

                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

            </service>

        </services>

        <behaviors>

            <serviceBehaviors>

                <behavior name="ServerWcfService.Services.MySimpleServiceBehavior">

                    <serviceMetadata httpGetEnabled="true"/>

                    <serviceDebug includeExceptionDetailInFaults="false"/>

                    <serviceCredentials>

                        <serviceCertificate findValue="MyServerCert" x509FindType="FindBySubjectName"storeLocation="LocalMachine" storeName="My"/>

                        <userNameAuthentication userNamePasswordValidationMode="Custom"customUserNamePasswordValidatorType="ServerWcfService.CustomValidators.MyCustomValidator,ServerWcfService"/>

                    </serviceCredentials>

                </behavior>

            </serviceBehaviors>

        </behaviors>

    </system.serviceModel>

4、客户端代码

protected void btnPrint_Click(object sender, EventArgs e)

{

TestWCFService.MySimpleServiceClient client = new ClientWeb.TestWCFService.MySimpleServiceClient();

client.ClientCredentials.UserName.UserName = "xiaozhuang";

client.ClientCredentials.UserName.Password = "123456";

lbMessage.Text = client.PrintMessage(txtMessage.Text);

}

如果你有一个真正的X509证书,那么现在的代码就可以正常运行了,但是测试需要进行如下的特殊处理

4.1、引用System.IdentityModel

4.2、建立一个新的类文件并继承自'System.IdentityModel.Selectors.X509CertificateValidator',然后我们重写里面的'Validate'方法来实现我们自己的X509认证逻辑

using System;

using System.Configuration;

using System.IdentityModel.Selectors;

using System.IdentityModel.Tokens;

using System.Security.Cryptography.X509Certificates;

 

 

namespace ClientWeb.CustomX509Validator

{

    /// <summary>

    /// Implements the validator for X509 certificates.

    /// </summary>

    public class MyX509ValidatorX509CertificateValidator

    {

        /// <summary>

        /// Validates a certificate.

        /// </summary>

        /// <param name="certificate">The certificate the validate.</param>

        public override void Validate(X509Certificate2 certificate)

        {

            // validate argument

            if (certificate == null)

                throw new ArgumentNullException("X509认证证书为空!");

 

            // check if the name of the certifcate matches

            if (certificate.SubjectName.Name != ConfigurationManager.AppSettings["CertName"])

                throw new SecurityTokenValidationException("Certificated was not issued by thrusted issuer");

        }

    }

}

4.3、配置文件

<behaviors>

            <endpointBehaviors>

                <behavior name="myClientBehavior">

                    <clientCredentials>

                        <serviceCertificate>

                            <authentication certificateValidationMode="Custom"customCertificateValidatorType="ClientWeb.CustomX509Validator.MyX509Validator,ClientWeb" />

                        </serviceCertificate>

                    </clientCredentials>

                </behavior>

            </endpointBehaviors>

        </behaviors>