記錄一下我實現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證書, 並導入到服務端和客戶端"