记录一下我实现WCF用户认证与权限控制的实现方法, 也让其余网友少走一些弯路. 内容写得很是小白(由于我也是小白嘛), 比较详细, 方便WCF知识基础薄的朋友html
主要分为下面几个步骤 数据库
这里要解释一下为何要用X509证书: 由于咱们须要X509证书这种非对称密钥技术来实现WCF在Message传递过程当中的加密和解密,要否则用户名和密码就得在网络上明文传递!详细说明就是客户端把用户名和密码用公钥加密后传递给服务器端,服务器端再用本身的私钥来解密,而后传递给相应的验证程序来实现身份验证安全
0. 开发环境bash
Win7 64bit服务器
VS2010 或者更高网络
.Net Framework 4ide
1. 新建服务端测试
建立一个最基本的WCF服务, 我这里命名为 WCF_UserPassword, 接下来咱们将直接使用里面的GetData方法ui
直接按F5, 你就可使用WCF测试服务端, 看到服务已经可使用了加密
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 --> 文件-->添加/删除管理单元-->可用的管理单元 下面选择 证书 -->选择计算机帐户 --> 选择本地计算机--> 完成
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
4. 配置服务端App.config, 主要包括如下内容
4.1. 将basicHttpBinding 修改成wsHttpBinding
4.2. 建立一个新wsHttpBinding的配置, 命名为wsHttpBindingToUserPassword
这个的设置改动只有一个, 切换至 安全性Tab, 把MessageClientCredentialType 从 Windows 改成 UserName
在配置文件App.config 中显示的是
<binding name="wsHttpBindingToUserPassword"> <security> <message clientCredentialType="UserName" /> </security> </binding>
4.3. 服务行为中添加一个serviceCredentials(最核心的设置)
高级-->服务行为-->右键 空名称, 选择: 添加服务行为元素扩展
添加serviceCredentials
命名为 ServiceBehaviorToUserPassword
双击serviceCredentials进入编辑
将userNamePasswordValidationMode 改成 Custom, 将customUserNamePasswordValidatorType填入"WCF_UserPassword.MyCustomValidator,WCF_UserPassword"
展开serviceCredentials就能够看到serviceCertificate, 将FindValue填入MyServerCert, 将X509FindType从FindBySubjectDistinguishedName改成FindBySubjectName
默认状况下, 客户端须要使用信任链对证书进行验证, 但因为导入到客户端的证书是咱们本身建立的, 不具备可验证的信任链, 因此须要继续修改clientCertificate, CertificateValidationMode改成PeerTrust(只有证书在TrustedPeople 就彻底信任), 将FindValue填入MyServerCert, StoreLocation改成LocalMachine, StoreName改成TrustedPeople, 将X509FindType从FindBySubjectDistinguishedName改成FindBySubjectName
4.4. 将以上添加的节点配置到服务中去
ServiceBehaviorToUserPassword 配置到 服务的behaviorConfiguration
将wsHttpBindingToUserPassword配置到终结点的bindingConfiguration
4.5. 将终结点的Dns从默认的localhost改成MyServerCert
5. 如今你能够运行服务端了, 调用GetData方法将弹出 "指定用户名" 的错误, 这表示咱们服务端的配置起效了
6. 从新打开一个Visual Studio, 新建一个Console控制台程序, 命名为WCF_Client
运行服务端, 以方便客户端获取服务信息, 服务地址通常都很长, 仍是直接复制服务地址吧
控制台程序的引用上添加服务引用
就直接使用默认的命名ServiceReference1吧
让咱们看看客户端代码
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); } }
运行结果
源代码 WCF_Course帐户密码认证.rar, 运行程序, 至少须要你完整完成第二步 "生成X.509证书, 并导入到服务端和客户端"