[WCF权限控制]ASP.NET Roles授权[下篇]
在采用Windows认证的情况下,使用基于Windows用户组安全主体权限模式是一个不错的选择。我们可以直接使用现有的用户组设置,也可以为相应的应用或服务创建单独的用户组。但是,由于该模式对Windows认证的依赖,意味着这种模式只能使用于局域网环境中。如果采用证书和Windows帐号的映射,也可以适用于像B2B这样的外部网环境。在其他的网络环境中,基于Windows用户组的授权方式将会无能为力。此外,还具有这样一种状况:即使是在同一个局域网环境中,并且也采用Windows进行客户端认证,但是我们不想创建太多的Windows用户组,而是将用户的权限信息维护在相应的数据库中,通过单独的安全系统来维护。在这种情况下,基于ASP.NET角色管理模块的授权模式是一个不错的选择。
目录: 一、 ASP.NET Roles提供程序 二、 ASP.NET Roles授权与认证的无关性 三、 ASP.NET Roles授权 在ServiceAuthorizationBehavior中的设定
一、ASP.NET Roles提供程序
和Membership一样,Roles也是ASP.NET一个重要的提供程序,旨在解决对角色的维护和基于角色的授权。ASP.NET Roles同样采用策略设计模式,角色的添加、删除、获取以及授权功能定义在System.Web.Security.RoleProvider这个抽象类中。而ASP.NET默认提供了如下三个具体的RoleProvider,它们同时也体现了角色和授权信息的三种不同的存储形式。如果它们还不能满足你的具体授权要求,你还可以自定义RoleProvider。比如说,如果你使用的数据库是Oracle,你可以参考SqlRoleProvider自定义一个OracleRoleProvider。
- SqlRoleProvider:将角色和授权信息存储于SQL Server数据库预定义的表中;
- WindowsTokenRoleProvider:直接使用Windows用户组进行授权,这是一个只读的RoleProvider,角色(用户组)的添加和删除操作是不允许的;
- AuthorizationStoreRoleProvider:使用Authorization Manager(AzMan)库做作为角色存储。
ASP.NET Roles相关的功能基本上都可以通过调用Roles这个静态类的相应的方法来完成。下面的代码片断列出了Roles的主要方法。其中CreateRole和DeleteRole用于进行角色创建和删除;RoleExists用户确定指定的角色是否存在;而AddUser(s)ToRole(s)和RemoveUser(s)FromRole(s)则用以建立和解除用户和角色的关系。而IsUserInRole用以确定指定的用户具有相应的角色。
1: public static class Roles
2: {
3: //其他成员
4: public static void CreateRole(string roleName);
5: public static bool DeleteRole(string roleName);
6: public static bool DeleteRole(string roleName, bool throwOnPopulatedRole);
7: public static bool RoleExists(string roleName);
8:
9: public static void AddUsersToRole(string[] usernames, string roleName);
10: public static void AddUsersToRoles(string[] usernames, string[] roleNames);
11: public static void AddUserToRole(string username, string roleName);
12: public static void AddUserToRoles(string username, string[] roleNames);
13:
14: public static void RemoveUserFromRole(string username, string roleName);
15: public static void RemoveUserFromRoles(string username, string[] roleNames);
16: public static void RemoveUsersFromRole(string[] usernames, string roleName);
17: public static void RemoveUsersFromRoles(string[] usernames, string[] roleNames);
18:
19: public static bool IsUserInRole(string roleName);
20: public static bool IsUserInRole(string username, string roleName);
21: }
针对Roles的方法AddUser(s)ToRole(s),有一点值得一提:这四个方法并不会进行用户账号存在与否的验证。原因很简单,用户账号的管理属于Membership的范畴,而建立用户与角色的关系才是属于角色管理需要负责的。Membership和Roles对于ASP.NET是相互独立的两个提供程序,它们不具有任何依赖关系。你完全可以采用ActiveDirectoryMembershipProvider利用AD进行用户账号管理和认证,而采用将角色维护在基于SqlRoleProvider的SQL Server数据表中。在这着情况下,当我们调用Roles的AddUser(s)ToRole(s)方法的时候,指定的用户帐号在数据库中是不存在的。所以,Roles不会进行用户存在与否的验证,它只是负责将指定的用户名添加到相应的角色之中而以。Membership和Roles的这种独立性同样体现在WCF上。
二、ASP.NET Roles授权与认证的无关性
通过前面的介绍我们很清楚地知道了Windows用户组授权依赖于Windows认证,但是如果你采用了ASP.NET Roles安全主体权限模式,你可以采用任何非匿名客户端凭证和认证方式。也就是说,ASP.NET Roles模式真正体现了认证和授权的无关性。
在采用ASP.NET Roles安全主体权限模式下,最终创建并作为当前线程安全主体的是一个RoleProviderPrincipal对象。而该RoleProviderPrincipal的Identity与当前ServiceSecurityContext的PrimaryIdentity属性实际上是同一个对象。两者的统一性可以通过于如下的验证程序来体现。
1: IIdentity identity1 = Thread.CurrentPrincipal.Identity;
2: IIdentity identity2 = ServiceSecurityContext.Current.PrimaryIdentity;
3: Debug.Assert(object.ReferenceEquals(identity1,identity2));
原则上,只要通过本认证的用户名能够通过ASP.NET Roles正确获取到反映权限的角色列表,授权就能顺利进行。如果采用Windows认证(包括之前提到的三种情况),你需要针对Windows帐号(域名/用户名)进行角色分配。如果采用基于Membership和Custom的用户名/密码认证,则直接针对用户名角色的分配。如果采用证书凭证并不允许Windows帐号映射,那么被认证的用户名是证书主体名称和指纹的组合(<<主题名称>>; <<指纹>>),你需要以此进行权限(角色)的设置。
三、ASP.NET Roles授权 在ServiceAuthorizationBehavior中的设定
之前已经说过了,所有基于安全主体授权的编程都体现在ServiceAuthorizationBehavior这个服务行为上。如果要让WCF采用ASP.NET Roles进行授权,我们需要将ServiceAuthorizationBehavior的PrincipalPermissionMode属性设置成PrincipalPermissionMode.UseAspNetRoles,并为其RoleProvider属性指定一个具体的RoleProvider。至于RoleProvider的获取,你可以通过Roles的Provider得到默认的RoleProvider。此外,Roles还具有一个类似于字典类型的Providers属性返回所有配置的RoleProvider列表,你可以通过传入配置名称获取相应的RoleProvider。
1: public sealed class ServiceAuthorizationBehavior : IServiceBehavior
2: {
3: //其他成员
4: public PrincipalPermissionMode PrincipalPermissionMode { get; set; }
5: public RoleProvider RoleProvider { get; set; }
6: }
7: public static class Roles
8: {
9: //其他成员
10: public static RoleProvider Provider { get; }
11: public static RoleProviderCollection Providers { get; }
12: }
下面给出的是一段基于自我寄宿的代码。在开启ServiceHost之前,我们为服务指定了一个ServiceAuthorizationBehavior行为,并将其安全主体权限模式设置成PrincipalPermissionMode.UseAspNetRoles,该ServiceAuthorizationBehavior使用当前配置的默认RoleProvider。
1: using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
2: {
3: host.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.UseAspNetRoles;
4: host.Authorization.RoleProvider = Roles.Provider
5: host.Open();
6: //...
7: }
我们还是一如既往地推荐采用配置的方式进行服务授权的设置。在下面这段配置中,我们在<system.web>/<roleManager>节点下配置了一个唯一的类型为SqlRoleProvider的RoleProvider。该SqlRoleProvider的配置名称为sqlRoleProvider,而目标数据库对应的连接字符串名称为aspNetDb。而ServiceAuthorizationBehavior配置在名称为aspNetRolesAuthorization的服务行为配置节中,反映其安全主体权限模式的principalPermissionMode属性被设置成UseAspNetRoles,而roleProviderName属性则正是配置的RoleProvider的名称。
1: <configuration>
2: <connectionStrings>
3: <add name="aspNetDb" connectionString="..." providerName="System.Data.SqlClient"/>
4: </connectionStrings>
5: <system.web>
6: <roleManager enabled="true" defaultProvider="SqlRoleProvider">
7: <providers>
8: <add name="sqlRoleProvider"
9: type="System.Web.Security.SqlRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
10: connectionStringName="aspNetDb" applicationName="AspRolesAuthorizationDemo"/>
11: </providers>
12: </roleManager>
13: </system.web>
14: <system.serviceModel>
15: <services>
16: <service name="Artech.WcfServices.Services.CalculatorService" behaviorConfiguration="aspNetRolesAuthorization">
17: <endpoint address="http://127.0.0.1/calculatorservice" binding="ws2007HttpBinding"
18: contract="Artech.WcfServices.Contracts.ICalculator"/>
19: </service>
20: </services>
21: <behaviors>
22: <serviceBehaviors>
23: <behavior name="aspNetRolesAuthorization">
24: <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="sqlRoleProvider"/>
25: </behavior>
26: </serviceBehaviors>
27: </behaviors>
28: </system.serviceModel>
29: </configuration>
- 使用Spring Cloud搭建服务注册中心
- 技术分享 | kafka的使用场景以及生态系统
- WebSocket刨根问底(二)
- WebSocket刨根问底(三)之群聊
- SDNLAB群分享(四):利用ODL下发流表创建VxLAN网络
- 一个简单的案例带你入门Dubbo分布式框架
- Ajax上传图片以及上传之前先预览
- Spring Cloud中Hystrix的服务降级与异常处理
- Open vSwitch源码解析之基于VxLAN实现NSH解析功能
- Spring Cloud自定义Hystrix请求命令
- JavaScript面试问题:事件委托和this
- Spring Cloud中的断路器Hystrix
- js的隐含参数(arguments,callee,caller)使用方法
- Spring Cloud中的负载均衡策略
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Discourse 如何使用命令行方式进行恢复
- CentOS 8 Apache 启用 SSL
- leetcode栈之二叉树的前序遍历
- 前端学数据结构与算法(七): 从零实现优先队列-堆及其应用
- 前端学数据结构与算法(六):二叉树的四种遍历方式及其应用
- 前端学数据结构与算法(五):理解二叉树特性及从零实现二叉搜索树
- 前端学数据结构与算法(四):理解递归及拿力扣链表题目练手
- 前端学数据结构与算法(三):链表为什么能和数组相提并论?用链表实现数组bettle下
- 前端学数据结构与算法(二):数组的操作特性与栈的应用
- 前端学数据结构与算法(一):不会复杂度分析,算法等于白学
- 高可扩展性系统的设计
- Vue如何实现导出页面为PDF
- 短视频APP开发,如何做到获取播放视频和音频文件
- 3分钟短文:Laravel模型创建数据条目的2个语法糖
- leetcode队列之最近的请求次数