閱讀689 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[WCF權限控製]ASP.NET Roles授權[下篇]

為了讓讀者對基於ASP.ENT Roles授權方式有一個全麵的認識,我們現在來做一個實例演示。在這個實例中,我們將采用不同的認證方式,包括Windows認證和證書認證()。簡單起見,我們依然沿用一貫的基於如下圖所示的解決方案結構,並且依然采用聲明式的授權。所以在服務操作方法Add上通過應用PrincipalPermissionAttribute特性指定其被授權的角色Administrators。

image

   1: public class CalculatorService : ICalculator
   2: {
   3:     [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
   4:     public double Add(double x, double y)
   5:     {
   6:         return x + y;
   7:     }
   8: }

我們具體采用的RoleProvider為SqlRoleProvider。為此,我們首先需要做的就是創建相應的數據庫。ASP.NET所有提供程序(比如Membership、Roles、Profile和Site Map等)所用的數據庫的初始化工作都可以通過這個工具來生成。當你創建了數據庫之後,你需要在aspnet_Applications表中插入一條記錄,以表示我們我們即將演示的應用。你可以直接執行如下的一段SQL腳本,在該校本中我們將演示應用起名為。

   1: INSERT INTO [aspnet_Applications]
   2:            ([ApplicationName]
   3:            ,[LoweredApplicationName]
   4:            ,[ApplicationId]
   5:            ,[Description])
   6: VALUES
   7:            (
   8:              'AspRolesAuthorizationDemo'
   9:              ,'asprolesauthorizationdemo '
  10:              ,NEWID()
  11:              ,''
  12:         )

我們授權演示的是在客戶端憑證類型為Windows的情況下采用ASP.NET Roles授權模式,為此我們需要更新一下服務端和客戶端的配置。注意不要忘了將根據你的實際情況修正連接字符串。下麵是服務端配置。

   1: <?xml version="1.0"?>
   2: <configuration>
   3:   <connectionStrings>
   4:     <add name="aspNetDb" connectionString="..." providerName="System.Data.SqlClient"/>
   5:   </connectionStrings>
   6:   <system.web>    
   7:     <roleManager enabled="true" defaultProvider="sqlRoleProvider">
   8:       <providers>
   9:         <add name="sqlRoleProvider" 
  10: type="System.Web.Security.SqlRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
  11: connectionStringName="AspNetDb" applicationName="AspRolesAuthorizationDemo"/>
  12:       </providers>
  13:     </roleManager>
  14:   </system.web>
  15:   <system.serviceModel>  
  16:     <services>
  17:       <service name="Artech.WcfServices.Services.CalculatorService" behaviorConfiguration="useAspNetRoles">
  18:         <endpoint address="https://127.0.0.1/calculatorservice" binding="ws2007HttpBinding" 
  19: contract="Artech.WcfServices.Contracts.ICalculator"/>
  20:       </service>
  21:     </services>
  22:     <behaviors>
  23:       <serviceBehaviors>
  24:         <behavior  name="useAspNetRoles">          
  25:           <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="sqlRoleProvider"/>
  26:         </behavior>
  27:       </serviceBehaviors>
  28:     </behaviors>
  29:   </system.serviceModel>
  30: </configuration>

下麵是客戶端配置。

   1: <?xml version="1.0"?>
   2: <configuration>
   3:   <system.serviceModel>   
   4:     <client>
   5:       <endpoint name="calculatorService" address="https://127.0.0.1/calculatorservice" binding="ws2007HttpBinding" 
   6: contract="Artech.WcfServices.Contracts.ICalculator"/>
   7:     </client>   
   8:   </system.serviceModel>
   9: </configuration>

在這之前我們需要創建了兩個Windows帳號Foo和Bar,密碼為Password。由於我們現在是采用ASP.NET Roles進行授權,我們需要通過Roles這個靜態類為他們分配相應的權限。為了省事,我直接將相應的實現寫在如下所示的服務寄宿程序中。在這段代碼中,如果Administrators角色不存在,先創建它,並將其分配給用戶Jinnan-PC\Foo(Jinnan-PC為我的機器名,對於域帳號,用域名替換)。

   1: if (!Roles.RoleExists("Administrators"))
   2: {
   3:     Roles.CreateRole("Administrators");
   4: }
   5: if(!Roles.IsUserInRole(@"Jinnan-PC\Foo","Administrators"))
   6: {
   7:     Roles.AddUserToRole(@"Jinnan-PC\Foo","Administrators");
   8: }
   9: using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
  10: {
  11:     host.Open();
  12:     Console.Read();
  13: }

然後客戶端分別以Foo和Bar的名義進行兩次服務調用,下麵是客戶端程序:

   1: ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorService");
   2: NetworkCredential credential = channelFactory.Credentials.Windows.ClientCredential;
   3: credential.UserName = "Foo";
   4: credential.Password = "Password";
   5: ICalculator calculator = channelFactory.CreateChannel();
   6: Invoke(calculator);
   7:  
   8: channelFactory = new ChannelFactory<ICalculator>("calculatorService");
   9: credential = channelFactory.Credentials.Windows.ClientCredential;
  10: credential.UserName = "Bar";
  11: credential.Password = "Password";
  12: calculator = channelFactory.CreateChannel();
  13: Invoke(calculator);

其中Invoke方法定義如下:

   1: static void Invoke(ICalculator calculator)
   2: {
   3:     try
   4:     {
   5:         calculator.Add(1,2);
   6:         Console.WriteLine("服務調用成功...");
   7:     }
   8:     catch (Exception ex)
   9:     {
  10:         Console.WriteLine("服務調用失敗...");
  11:     }
  12: }

由於Foo在服務啟動之初就已經分配了Adminstrators角色,而Bar沒有,所以隻有第一次服務調用能夠成功。而最終的執行結果也印證了這一點。

   1: 服務調用成功...
   2: 服務調用失敗...

接下來我們來演示客戶端使用X.509證書的情況下如何使用ASP.ENT Roles授權。為此我們需要通過如下的命令行創建三個主題名稱(CN)分別為Jinnan-PC(你可以任意指定該證書主體名稱)、Foo和Bar的證書。第一個作為服務證書,後兩個坐位客戶端證書。它們都自動保存到本機(LocalMachine)的個人證書存儲區。然後我們利用MMC的證書管理單元將Foo和Bar兩證書導入到受信任人(Trusted People)證書存儲區。

   1: MakeCert –n “CN=Jinnan-PC” –sr LocalMachine –ss My –pe –sky exchange
   2: MakeCert –n “CN=Foo” –sr LocalMachine –ss My –pe –sky exchange
   3: MakeCert –n “CN=Bar” –sr LocalMachine –ss My –pe –sky exchange

為了采用X.509證書作為客戶端憑證,我們需要修改服務端和客戶端的配置。在服務端配置中,不僅僅通過服務行為進行基於ASP.NET Roles授權相應的設置,還為服務設置了服務證書(Jinnan-PC),以及針對證書的認證模式(PeerOrChainTrust)。而客戶端則將服務證書的認證模式設為None。下麵是服務端配置。

   1: <?xml version="1.0"?>
   2: <configuration>
   3:   <connectionStrings>
   4:     <add name="AspNetDb" connectionString="..." providerName="System.Data.SqlClient"/>
   5:   </connectionStrings>
   6:   <system.web>    
   7:     <roleManager enabled="true" defaultProvider="SqlRoleProvider">
   8:       <providers>
   9:         <add name="sqlRoleProvider" 
  10: type="System.Web.Security.SqlRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
  11: connectionStringName="AspNetDb" applicationName="AspRolesAuthorizationDemo"/>
  12:       </providers>
  13:     </roleManager>
  14:     </system.web>
  15:   <system.serviceModel>
  16:     <bindings>
  17:       <ws2007HttpBinding>
  18:         <binding name="certificateCredentialBinding">
  19:           <security mode="Message">
  20:             <message clientCredentialType="Certificate"/>
  21:           </security>
  22:         </binding>
  23:       </ws2007HttpBinding>
  24:     </bindings>
  25:     <services>
  26:       <service name="Artech.WcfServices.Services.CalculatorService" behaviorConfiguration="useAspNetRoles">
  27:         <endpoint address="https://127.0.0.1/calculatorservice" binding="ws2007HttpBinding" bindingConfiguration="certificateCredentialBinding" 
  28: contract="Artech.WcfServices.Contracts.ICalculator"/>
  29:       </service>
  30:     </services>
  31:     <behaviors>
  32:       <serviceBehaviors>
  33:         <behavior  name="useAspNetRoles">
  34:           <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="sqlRoleProvider"/>
  35:           <serviceCredentials>
  36:             <serviceCertificate storeLocation="LocalMachine" storeName ="My" x509FindType="FindBySubjectName" findValue="Jinnan-PC"/>
  37:             <clientCertificate>
  38:               <authentication certificateValidationMode="PeerOrChainTrust"/>
  39:             </clientCertificate>
  40:           </serviceCredentials>
  41:         </behavior>
  42:       </serviceBehaviors>
  43:     </behaviors>
  44:   </system.serviceModel>
  45: </configuration>

下麵是客戶端配置。

   1: <?xml version="1.0"?>
   2: <configuration>
   3:   <system.serviceModel>
   4:     <bindings>
   5:       <ws2007HttpBinding>
   6:         <binding name="certificateCredentialBinding">
   7:           <security mode="Message">
   8:             <message clientCredentialType="Certificate"/>
   9:           </security>
  10:         </binding>
  11:       </ws2007HttpBinding>
  12:     </bindings>
  13:     <client>
  14:       <endpoint name="calculatorService" behaviorConfiguration="ignoreCertValidation" 
  15: address="https://127.0.0.1/calculatorservice" binding="ws2007HttpBinding" bindingConfiguration="certificateCredentialBinding" 
  16: contract="Artech.WcfServices.Contracts.ICalculator">
  17:         <identity>
  18:           <certificateReference storeLocation="LocalMachine" storeName ="My" x509FindType="FindBySubjectName" findValue="Jinnan-PC"/>
  19:         </identity>
  20:       </endpoint>
  21:     </client>
  22:     <behaviors>
  23:       <endpointBehaviors>
  24:         <behavior name="ignoreCertValidation">
  25:           <clientCredentials>
  26:             <serviceCertificate>
  27:               <authentication certificateValidationMode="None"/>
  28:             </serviceCertificate>
  29:           </clientCredentials>
  30:         </behavior>
  31:       </endpointBehaviors>
  32:     </behaviors>
  33:   </system.serviceModel>
  34: </configuration>

現在我需要做的是通過Roles這個靜態類型對以證書表示的兩個用戶進行角色的分配。之前我們已經說過,當客戶端采用證書作為客戶端憑證的情況下,用戶名稱得格式為(<<主題名稱>>; <<指紋>>)。Foo的主題名稱為CN=Foo,你可以通過MMC的證書管理單元查看證書的指紋,比如指紋內容為50819320DAAF1BAD9DE8823D3216BE9B36760C4D。那麼我們隻需要針對用戶名“”進行授權就可以了。我們一樣將角色分配實現在服務寄宿程序中。

   1: if (!Roles.RoleExists("Administrators"))
   2: {
   3:     Roles.CreateRole("Administrators");
   4: }
   5: if (!Roles.IsUserInRole("CN=Foo; 50819320DAAF1BAD9DE8823D3216BE9B36760C4D", "Administrators"))
   6: {
   7:     Roles.AddUserToRole("CN=Foo; 50819320DAAF1BAD9DE8823D3216BE9B36760C4D", "Administrators");
   8: }
   9: using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
  10: {
  11:     host.Open();
  12:     Console.Read();
  13: }

然後客戶端分別使用針對Foo和Bar兩張不同證書作為憑證進行服務調用,相應的客戶端程序如下所示。根據權限的不同,也隻有第一次服務調用能夠成功。

客戶端程序:

   1: ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorService");
   2: channelFactory.Credentials.ClientCertificate.SetCertificate( StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName,"Foo");
   3: ICalculator calculator = channelFactory.CreateChannel();
   4: Invoke(calculator);
   5:  
   6: channelFactory = new ChannelFactory<ICalculator>("calculatorService");
   7: channelFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "Bar");   
   8: calculator = channelFactory.CreateChannel();
   9: Invoke(calculator);

輸出結果:

   1: 服務調用成功...
   2: 服務調用失敗...

 

[WCF權限控製]ASP.NET Roles授權[上篇]
[WCF權限控製]ASP.NET Roles授權[下篇]


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-26 16:34:02

  上一篇:go  [WCF權限控製]ASP.NET Roles授權[上篇]
  下一篇:go  [WCF權限控製]通過擴展自行實現服務授權[提供源碼下載]