WCF授权-ASP.NET Roles授权[下篇]
为了让读者对基于ASP.ENT Roles授权方式有一个全面的认识,我们现在来做一个实例演示。在这个实例中,我们将采用不同的认证方式,包括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创建数据库
我们具体采用的RoleProvider为SqlRoleProvider。为此,我们首先需要做的就是创建相应的数据库。ASP.NET所有提供程序(比如Membership、Roles、Profile和Site Map等)所用的数据库的初始化工作都可以通过aspnet_regsql.exe这个工具来生成。当你创建了数据库之后,你需要在aspnet_Applications表中插入一条记录,以表示我们我们即将演示的应用。你可以直接执行如下的一段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>
在这之前我们需要创建了两个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授权
接下来我们来演示客户端使用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="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>
现在我需要做的是通过Roles这个静态类型对以证书表示的两个用户进行角色的分配。之前我们已经说过,当客户端采用证书作为客户端凭证的情况下, 用户名称得格式为(<<主题名称>>; <<指纹>>)。Foo的主题名称为CN=Foo,你可以通过MMC的证书管理单元查看证书的指纹,比如指纹内容为 50819320DAAF1BAD9DE8823D3216BE9B36760C4D。那么我们只需要针对用户名“CN=Foo; 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: 服务调用失败...
出处:http://artech.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
加支付宝好友偷能量挖...