1. Transfer Security
Transfer Security 主要包括三個方面: "消息完整性(Message Integrity)"、"消息機密性 (Message Confidentiality)" 和 "交互驗證(Mutual Authentication)"。
消息完整性必須確保消息在傳輸過程中沒有被篡改,接收的消息是完整且正確的;消息機密性必須確保消息不會被任何第三方查閱,消息內容不會洩漏給任何非相關人員;而交互認證則是指客戶端和服務器必須通過某種信任機制才能建立正確的連接,同時交互認證還要監測並阻止拒絕服務攻擊(DOS)。通常的做法是對消息進行數字簽名來確保其完整性,使用非對稱加密算法來阻止消息內容外洩,而用戶名/密碼、X.509 數字證書等方式則可以用來驗證對方身份,在這裡我們主要講述如何在WCF中使用Membership provider的身份驗證方式.
2.使用 ASP.NET Membership Provider
ASP.NET Membership Provider是一種功能,可供 ASP.NET 開發人員用於創建允許用戶創建唯一用戶名和密碼組合的網站。使用此工具,任何用戶都可以在該網站上建立帳戶,並登錄網站以便獨占訪問該網站及其服務。這與要求用戶在 Windows 域中具有帳戶的 Windows 安全完全不同。所有提供憑據(用戶名/密碼組合)的用戶都可以使用該網站及其服務。在做這個Demo之前,我們需要創建本地的aspnetdb數據,使用vs2008的tool中的 command命令下執行:aspnet_regsql。這個命令會為我們本地創建一個名為aspnetdb的數據。同時我們使用ASP.Net configuration工具創建1個角色:角色名為:super user.建立一個用戶;user1.這個user1的角色是super user.具體關於membership provider方面的知識可以在MSDN是查找相關的知識,在這裡我們就不多說,事實上在WCF中,使用ASP.NET Membership Provider 和使用userName/password一樣的機制,同樣我們也需要在服務端裝上x509的證書。用以在傳輸過程中用於加密用戶名和密碼。
創建證書:makecert -r -pe -n "CN=MyServer" -ss My -sky exchange .
3.Solution 結構如下圖:
solution:WCFMembershipClient WCF client端 Console Application.
WCFMembershipServices WCF Application
Windows Communication Foundation (WCF) 開發人員可以出於安全目的利用這些功能。當集成到 WCF 應用程序中時,用戶必須向 WCF 客戶端應用程序提供用戶名/密碼組合。若要將數據傳輸到 WCF 服務,請使用支持用戶名/密碼憑據的綁定,如 WSHttpBinding 並將客戶端憑據類型設置為 UserName。在服務上,WCF 安全基於用戶名和密碼對用戶進行身份驗證,還會分配由 ASP.NET 角色指定的角色。
配置成員資格提供程序,加在服務端配置文件中
<connectionStrings> <add name="SqlConn" connectionString="Data Source=localhost;Integrated Security=true;database=aspnetdb;"/> </connectionStrings> <system.web> <!-- Configure the Sql Membership Provider --> <membership defaultProvider="SqlMembershipProvider" userIsOnlineTimeWindow="15"> <providers> <clear/> <add name="SqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="SqlConn" applicationName="MembershipAndRoleProviderSample" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed"/> </providers> </membership> <!-- Configure the Sql Role Provider --> <roleManager enabled="true" defaultProvider="SqlRoleProvider"> <providers> <add name="SqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="SqlConn" applicationName="WCFMembership"/> </providers> </roleManager> <compilation debug="true"/> </system.web>
創建服務
[ServiceContract] public interface IService1 {
[OperationContract] bool test(); }
public class Service1 : IService1//實現服務 { public Service1() { } #region IService1 Members
[PrincipalPermission(SecurityAction.Demand,Role="super user")] public bool test() { return true; } #endregion }
服務端的配置文件如下:
<system.serviceModel> <services> <service name="WCFMembershipServices.Service1" behaviorConfiguration="MembershipBehavior"> <!-- use base address provided by host --> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="WCFMembershipServices.IService1"/> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <bindings> <wsHttpBinding> <!-- Set up a binding that uses Username as the client credential type --> <binding name="Binding1"> <security mode="Message"> <message clientCredentialType="UserName"/> </security> </binding> </wsHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="MembershipBehavior"> <!-- Configure role based authorization to use the Role Provider --> <serviceAuthorization principalPermissionMode="None" roleProviderName="SqlRoleProvider"/> <serviceCredentials> <!-- Configure user name authentication to use the Membership Provider -->
//將 membershipProviderName 屬性設置為提供程序的名稱將 membershipProviderName 屬性設置為提供程序的名稱 <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="SqlMembershipProvider"/> <!-- Configure the service certificate --> <serviceCertificate storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName" findValue="MyServer"/> </serviceCredentials> <!--For debugging purposes set the includeExceptionDetailInFaults attribute to true--> <serviceDebug includeExceptionDetailInFaults="false"/> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
4. 創建客戶端
<system.serviceModel> <client> <endpoint name="" address="http://localhost:51991/Service1.svc" behaviorConfiguration ="ClientBehavior" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="IService1" > <identity> <certificate encodedValue="AwAAAAEAAAAUAAAAqxw7daba6mcItJ/tKIAFZfz" </identity> </endpoint> </client> <behaviors> <endpointBehaviors> <behavior name="ClientBehavior"> <clientCredentials> <serviceCertificate> <authentication certificateValidationMode="None" /> </serviceCertificate> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <bindings> <wsHttpBinding> <!-- Set up a binding that uses Username as the client credential type --> <binding name="Binding1"> <security mode ="Message"> <message clientCredentialType ="UserName" /> </security> </binding> </wsHttpBinding> </bindings> </system.serviceModel>
客戶端代理由Svcutil工具生成的,在這裡就不貼出來了。在vs2008的tool command中可以svcutil +‘元數據地址’就為幫你生成的。
Service1Client client = new Service1Client(); client.ClientCredentials.UserName.UserName = "user1"; client.ClientCredentials.UserName.Password = "@abc123"; client.test();
這樣就可以成功能調用了:如果能成功能過驗證的話