zoukankan      html  css  js  c++  java
  • WCF账户密码认证

    记录一下我实现WCF用户认证与权限控制的实现方法, 也让其他网友少走一些弯路. 内容写得非常小白(因为我也是小白嘛), 比较详细, 方便WCF知识基础薄的朋友

    主要分为下面几个步骤

    1. 作为例子, 创建最简单的WCF服务
    2. 生成X.509证书, 并导入到服务端和客户端
    3. 为服务提供帐号密码验证程序, 并配置App.config
    4. 生成客户端并配置其App.config

    这里要解释一下为什么要用X509证书: 因为我们需要X509证书这种非对称密钥技术来实现WCF在Message传递过程中的加密和解密,要不然用户名和密码就得在网络上明文传递!详细说明就是客户端把用户名和密码用公钥加密后传递给服务器端,服务器端再用自己的私钥来解密,然后传递给相应的验证程序来实现身份验证

    0. 开发环境

    Win7 64bit

    VS2010 或者更高

    .Net Framework 4

    1. 新建服务端

    创建一个最基本的WCF服务, 我这里命名为 WCF_UserPassword, 接下来我们将直接使用里面的GetData方法

    image

    直接按F5, 你就可以使用WCF测试服务端, 看到服务已经可以使用了

    image

    2. 生成X.509证书, 并导入到服务端和客户端

    生成X509证书需要用到makecert.exe, 只要安装了Visual Studio, 就可以在C盘找到, 为了操作方便, 将它拷贝到 D:Cert; 安装证书需要用到CertMgr.exe, 所以也拷贝进来吧, 这两个exe都有32位版本和64位版本, 请拷贝与自己系统一致的版本; 最后还要用到pvk2pfx.exe, 这个只有32位版本(VS2013 又有64位版本)

    2.1. 服务端和客户端 在同一台电脑上的情况

    在服务端生成X.509证书

    打开CMD, 切换到D:Cert\, 运行下面这个命令

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

    这个命令的意思就是创建一个测试的X509证书,这个证书放在存储位置为"Localmachine"(本地计算机)的"My"(个人)这个证书文件夹下,证书主题名字叫"MyServerCert"

    你可以通过mmc查看是否安装成功, 运行mmc --> 文件-->添加/删除管理单元-->可用的管理单元 下面选择 证书 -->选择计算机账户 --> 选择本地计算机--> 完成

    image

    2.2. 将服务器证书公匙安装到客户端的 受信任人的存储区中

    certmgr.exe -add -r LocalMachine -s My -c -n MyServerCert -r LocalMachine -s TrustedPeople

    因为客户端系统不隐式信任 Makecert.exe 生成的证书,所以需要执行此步骤。如果您已经拥有一个证书,该证书来源于客户端的受信任根证书(例如由 Microsoft 颁发的证书),则不需要执行使用服务器证书填充客户端证书存储区这一步骤。

    2.3. 服务端和客户端 在不同电脑上 的情况(这个例子里没有用到这节内容)

    生成密匙

    makecert -r -pe -sky exchange -n "CN=MyServerCert" MyServerCertPublicKey.cer -sv MyServerCertPrivateKey.pvk
    pvk2pfx.exe -pvk MyServerCertPrivateKey.pvk -spc MyServerCertPublicKey.cer -pfx MyServerCertExchange.pfx

    你将得到

    MyServerCertExchange.pfx     //密匙交换文件
    MyServerCertPrivateKey.pvk    //私匙
    MyServerCertPublicKey.cer     //公匙

    在服务端: 将MyServerCertExchange.pfx导入到 本地计算机证书 -->个人--> 证书

    CMD: certmgr.exe -add -c MyServerCertExchange.pfx -r LocalMachine -s my

    在客户端: 将MyServerCertPublicKey.cer 导入到 本地计算机证书 --> 受信任人-->证书

    CMD: certmgr.exe -add -c MyServerCertPublicKey.cer -r LocalMachine -s TrustedPeople

    3. 添加验证程序

    添加一个 继承自System.IdentityModel.Selectors.UserNamePasswordValidator 的MyCustomValidator 类, 重写里面的Validate方法来实现用户名密码认证逻辑

    using System.IdentityModel.Selectors;
    using System.IdentityModel.Tokens;
    using System.ServiceModel;
    
    namespace WCF_UserPassword
    {
        public class MyCustomValidator : UserNamePasswordValidator
        {
            public override void Validate(string userName, string password)
            {
                //这里仅简单演示一下, 实际工作中应该是使用 数据库查询 
                if (userName == "admin" && password == "admin") return;
                if (userName == "admin2" && password == "admin2") return;
                
                throw new FaultException("用户名或者密码错误!");
                //throw new SecurityTokenException("用户名或者密码错误!"); //这种异常, 客户端将不能得到 错误信息
            }
        }
    }

    这需要添加引用 System.IdentityModel.dll

    image

    4. 配置服务端App.config, 主要包括以下内容

    1. 将basicHttpBinding 修改为wsHttpBinding
    2. 创建一个新wsHttpBinding的配置
    3. 服务行为中添加一个serviceCredentials

    4.1. 将basicHttpBinding 修改为wsHttpBinding

    image

    4.2. 创建一个新wsHttpBinding的配置, 命名为wsHttpBindingToUserPassword

    image

    这个的设置改动只有一个, 切换至 安全性Tab, 把MessageClientCredentialType 从 Windows 改为 UserName

    image

    在配置文件App.config 中显示的是

    <binding name="wsHttpBindingToUserPassword">
      <security>
        <message clientCredentialType="UserName" />
      </security>
    </binding>

    4.3. 服务行为中添加一个serviceCredentials(最核心的设置)

    高级-->服务行为-->右键 空名称, 选择: 添加服务行为元素扩展

    image

    添加serviceCredentials

    image

    命名为 ServiceBehaviorToUserPassword

    image

    双击serviceCredentials进入编辑

    image

    将userNamePasswordValidationMode 改为 Custom, 将customUserNamePasswordValidatorType填入"WCF_UserPassword.MyCustomValidator,WCF_UserPassword"

    image

    展开serviceCredentials就可以看到serviceCertificate, 将FindValue填入MyServerCert, 将X509FindType从FindBySubjectDistinguishedName改为FindBySubjectName

    image

    默认情况下, 客户端需要使用信任链对证书进行验证, 但由于导入到客户端的证书是我们自己创建的, 不具有可验证的信任链, 所以需要继续修改clientCertificate, CertificateValidationMode改为PeerTrust(只有证书在TrustedPeople 就完全信任), 将FindValue填入MyServerCert, StoreLocation改为LocalMachine, StoreName改为TrustedPeople, 将X509FindType从FindBySubjectDistinguishedName改为FindBySubjectName

    image

    4.4. 将以上添加的节点配置到服务中去

    ServiceBehaviorToUserPassword 配置到 服务的behaviorConfiguration

    image

    将wsHttpBindingToUserPassword配置到终结点的bindingConfiguration

    image

    4.5. 将终结点的Dns从默认的localhost改为MyServerCert

    image

    5. 现在你可以运行服务端了, 调用GetData方法将弹出 "指定用户名" 的错误, 这表示我们服务端的配置起效了

    image

    6. 重新打开一个Visual Studio, 新建一个Console控制台程序, 命名为WCF_Client

    运行服务端, 以方便客户端获取服务信息, 服务地址一般都很长, 还是直接复制服务地址吧

    image

    控制台程序的引用上添加服务引用

    image

    就直接使用默认的命名ServiceReference1吧

    image

    让我们看看客户端代码

    static void Main(string[] args)
    {
        var proxy = new ServiceReference1.Service1Client();
        proxy.ClientCredentials.UserName.UserName = "admin";
        proxy.ClientCredentials.UserName.Password = "admin";
     
        try
        {
            Console.WriteLine(proxy.GetData(2));
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    运行结果

    image

    源代码 WCF_Course账户密码认证.rar, 运行程序, 至少需要你完整完成第二步 "生成X.509证书, 并导入到服务端和客户端"

  • 相关阅读:
    gc buffer busy/gcs log flush sync与log file sync
    给Oracle年轻的初学者的几点建议
    Android 编程下帧动画在 Activity 启动时自动运行的几种方式
    Android 编程下 Touch 事件的分发和消费机制
    Java 编程下 static 关键字
    Java 编程下 final 关键字
    Android 编程下模拟 HOME 键效果
    Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated ?
    Extjs4 大型项目目录结构重构
    [转]SQLServer 2008 允许远程连接的配置方法
  • 原文地址:https://www.cnblogs.com/zhouandke/p/5823930.html
Copyright © 2011-2022 走看看