[WCF權限控制]ASP.NET Roles授權[下篇]
為了讓讀者對基于ASP.ENT Roles授權方式有一個全面的認識,我們現(xiàn)在來做一個實例演示。在這個實例中,我們將采用不同的認證方式,包括Windows認證和證書認證(ASP.NET Membership + Roles為常見的組合方式,在這里就不多作演示)。簡單起見,我們依然沿用一貫的基于如下圖所示的解決方案結構,并且依然采用聲明式的授權。所以在服務操作方法Add上通過應用PrincipalPermissionAttribute特性指定其被授權的角色Administrators。
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: }
一、為SqlRoleProvider創(chuàng)建數(shù)據庫
我們具體采用的RoleProvider為SqlRoleProvider。為此,我們首先需要做的就是創(chuàng)建相應的數(shù)據庫。ASP.NET所有提供程序(比如Membership、Roles、Profile和Site Map等)所用的數(shù)據庫的初始化工作都可以通過aspnet_regsql.exe這個工具來生成。當你創(chuàng)建了數(shù)據庫之后,你需要在aspnet_Applications表中插入一條記錄,以表示我們我們即將演示的應用。你可以直接執(zhí)行如下的一段SQL腳本,在該校本中我們將演示應用起名為AspRolesAuthorizationDemo。
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.ENT Roles授權
我們授權演示的是在客戶端憑證類型為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="http://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="http://127.0.0.1/calculatorservice" binding="ws2007HttpBinding"
6: contract="Artech.WcfServices.Contracts.ICalculator"/>
7: </client>
8: </system.serviceModel>
9: </configuration>
在這之前我們需要創(chuàng)建了兩個Windows帳號Foo和Bar,密碼為Password。由于我們現(xiàn)在是采用ASP.NET Roles進行授權,我們需要通過Roles這個靜態(tài)類為他們分配相應的權限。為了省事,我直接將相應的實現(xiàn)寫在如下所示的服務寄宿程序中。在這段代碼中,如果Administrators角色不存在,先創(chuàng)建它,并將其分配給用戶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沒有,所以只有第一次服務調用能夠成功。而最終的執(zhí)行結果也印證了這一點。
1: 服務調用成功...
2: 服務調用失敗...
三、在X.509證書認證下使用ASP.ENT Roles授權
接下來我們來演示客戶端使用X.509證書的情況下如何使用ASP.ENT Roles授權。為此我們需要通過如下的命令行創(chuàng)建三個主題名稱(CN)分別為Jinnan-PC(你可以任意指定該證書主體名稱)、Foo和Bar的證書。第一個作為服務證書,后兩個坐位客戶端證書。它們都自動保存到本機(LocalMachine)的個人證書存儲區(qū)。然后我們利用MMC的證書管理單元將Foo和Bar兩證書導入到受信任人(Trusted People)證書存儲區(qū)。
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="http://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="http://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>
現(xiàn)在我需要做的是通過Roles這個靜態(tài)類型對以證書表示的兩個用戶進行角色的分配。之前我們已經說過,當客戶端采用證書作為客戶端憑證的情況下,用戶名稱得格式為(<<主題名稱>>; <<指紋>>)。Foo的主題名稱為CN=Foo,你可以通過MMC的證書管理單元查看證書的指紋,比如指紋內容為50819320DAAF1BAD9DE8823D3216BE9B36760C4D。那么我們只需要針對用戶名“CN=Foo; 50819320DAAF1BAD9DE8823D3216BE9B36760C4D”進行授權就可以了。我們一樣將角色分配實現(xiàn)在服務寄宿程序中。
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: 服務調用失敗...


為了讓讀者對基于ASP.ENT Roles授權方式有一個全面的認識,我們現(xiàn)在來做一個實例演示。在這個實例中,我們將采用不同的認證方式,包括Windows認證和證書認證(ASP.NET Membership + Roles為常見的組合方式,在這里就不多作演示)。

浙公網安備 33010602011771號