[WCF权限控制]WCF自定义授权体系详解[原理篇]
到目前为止,我么介绍的授权策略都是围绕着安全主体进行的,基本上都是基于角色的授权。虽然角色是定义权限最为常用的形式,但是它解决不了授权的所有问题。基于角色的授权策略一般是这样的:需要进行访问控制的操作或者资源关联到某个角色上,那么只要访问者被分配了该角色,就被授予了相应的权限。那么假设我们的授权策略是这样的:访问权限和两个角色进行关联,访问者需要同时被分配了这两个角色才能被授权。这是一个很常见的授权策略,但是典型的基于单一角色的授权解决不了这个问题(除非为两个角色的交集创建新的角色)。而这仅仅是一种简单的授权策略,有时候授权需要通过一个复杂的表达式来表示,而且其中会涉及诸多元素,比如身份、角色和组织等。
我之所以说这么多,主要是为说明一个问题:授权策略有时候需要手工定制。而作为一种基于可扩展性的通信框架,WCF在授权方面提供了扩展点,使你可以根据的你实际需要定制相应的授权策略。WCF为了创建了一个基于“声明”的授权系统,为了让读者对该系统的内部原理有全面的了解,我们不妨先来讨论一下这里指的声明是如何定义的。
目录: 一、Claim和ClaimSet 二、DispatchRuntime中的AuthorizationPolicy和ServiceAuthorizationManager 三、通过自定义AuthorizationPolicy创建基于自定义授权策略的声明 四、通过自定义ServiceAuthorizationManager根据声明作出最后的授权判断
一、Claim和ClaimSet
声明描述了与系统中某个实体关联的功能,该实体通常为该系统中的某个用户。通过对访问给定的受保护资源所需的声明和与试图进行访问的实体关联的声明进行比较,便可确定该资源的访问权限。声明是针对特定值的权限表达式。权限可以是读取、写入或拥有。值可以是数据库、文件、邮箱或属性。声明还具有声明类型。声明类型和权限的组合提供了用于针对该值指定的功能的机制。在WCF安全应用编程接口中,生命通过类型Claim表示。从下面给出的关于Claim定义的代码片断中,我们可以认识到:一个通过Claim对象表示的声明具有如下三要素:声明类型(ClaimType)、声明关联的资源(Resource)和声明代表的权限类型(Right)。
1: public class Claim
2: {
3: //其他成员
4: public string ClaimType { get; }
5: public object Resource { get; }
6: public string Right { get; }
7: }
通过Right属性表示的权限类型一般通过一个统一资源标识符(URI)来表示,而静态类Rights定义了两个预定义的权限类型:Identity和PossessProperty。前者表示声明用于身份标识,后者则表示声明关联的实体具有的属性。Rights类定义如下。
1: public static class Rights
2: {
3: public static string Identity { get; }
4: public static string PossessProperty { get; }
5: }
二、DispatchRuntime中的AuthorizationPolicy和ServiceAuthorizationManager
在上面我们已经提到过了,借助于WCF的扩展,我们通过自定义AuthorizationPolicy和ServiceAuthorizationManager来让WCF按照我们自定义的授权策略进行访问控制。那么。这两个对象是如何参与到WCF的授权执行流程中的呢?
我们首先需要了解的是:自定义的AuthorizationPolicy和ServiceAuthorizationManager通过服务行为ServiceAuthorizationBehavior成为WCF运行时的一部分。具体来说,在ServiceAuthorizationBehavior的ApplyDispatchBehavior方法被调用的时候,定义在ExternalAuthorizationPolicies属性中的AuthorizationPolicy列表和ServiceAuthorizationManager被赋值给所有终结点的分发运行时。在DispatchRuntime类型中,具有两个同名的属性。
1: public sealed class DispatchRuntime
2: {
3: //其他成员
4: public ReadOnlyCollection<IAuthorizationPolicy> ExternalAuthorizationPolicies { get; set; }
5: public ServiceAuthorizationManager ServiceAuthorizationManager { get; set; }
6: }
三、通过自定义AuthorizationPolicy创建基于自定义授权策略的声明
整个自定义授权先从AuthorizationPolicy开始。具体来说,WCF先创建一个EvaluationContext对象。我们之前只提到过EvaluationContext用于表示属性的Properties,实际上它的核心是通过ClaimSets属性表示的声明集(ClaimSet)的集合。下面给出的EvaluationContext的整个公用成员的定义,除了Properties和ClaimSets之前,EvaluationContext还具有一个额外的属性Generation表示声明集被添加到ClaimSets集合的次数。而声明集的添加通过方法AddClaimSet实现。EvaluationContext具有一个有效性,而失效的时间可以通过方法RecordExpirationTime来记录。
1: public abstract class EvaluationContext
2: {
3: public abstract void AddClaimSet(IAuthorizationPolicy policy, ClaimSet claimSet);
4: public abstract void RecordExpirationTime(DateTime expirationTime);
5:
6: public abstract ReadOnlyCollection<ClaimSet> ClaimSets { get; }
7: public abstract int Generation { get; }
8: public abstract IDictionary<string, object> Properties { get; }
9: }
EvaluationContext是一个抽象类型,实际被创建的是一个被称为System.IdentityModel.Policy.DefaultEvaluationContext的内部类型的对象。当EvaluationContext被初始化之后,WCF会遍历定义在当前DispatchRuntime的ExternalAuthorizationPolicies属性中的所有AuthorizationPolicy。然后依次调用它们的Evaluate方法,而传入的参数就是之前初始化的这个EvaluationContext对象。一般地,我们通过自定义AuthorizationPolicy的目的在于通过在实现的Evaluate方法中将基于你自定义授权策略相关的声明集添加到EvaluationContext的ClaimSets中。
四、通过自定义ServiceAuthorizationManager根据声明作出最后的授权判断
在所有的自定义AuthorizationPolicy的Evaluate方法被调用之后,最终的EvaluationContext对象被用以初始化当前的授权上下文(AuthorizationContext)。下面给出了AuthorizationContext的所有公共属性的定义。一般来说,除了Id,其余三个属性直接来源于EvaluationContext。具体来说,EvaluationContext的ClaimSets和Properties作为AuthorizationContext的ClaimSets和Properties,而EvaluationContext通过RecordExpirationTime记录的过期时间反应在AuthorizationContext的ExpirationTime上。
1: public abstract class AuthorizationContext : IAuthorizationComponent
2: {
3: public abstract string Id { get; }
4:
5: public abstract ReadOnlyCollection<ClaimSet> ClaimSets { get; }
6: public abstract DateTime ExpirationTime { get; }
7: public abstract IDictionary<string, object> Properties { get; }
8: }
和EvaluationContext一样,AuthorizationContext也是一个抽象类,默认被创建的是一个名称为System.IdentityModel.Policy.DefaultAuthorizationContext的内部类型对象。而通过EvaluationContext创建的AuthorizationContext最终服务于自定义的ServiceAuthorizationManager以实现最终授权的判断。具体来说,WCF通过调用ServiceAuthorizationManager的CheckAccess方法决定当前操作是否被授权访问。
- 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 数组属性和方法
- 重新加载故障节点上的 Ceph 卷
- 一个Spring Bean从诞生到逝去的九次人生转折!
- 原创 | 详解git rebase,让你走上git大神之路
- 启用chrome浏览器内置的二维码生成插件
- ZeroLogon漏洞(CVE-2020-1472)防御性指南
- 原创 | 随机数大家都会用,但是你知道生成随机数的算法吗?
- 原创 | codeforces 1425E,一万种情况的简单题
- 原创 | codeforces 1417C,逆向思考的数据结构题
- 原创 | 操作失误不要慌,这个命令给你的Git一次反悔的机会
- 原创 | 想做推荐算法?先把FM模型搞懂再说
- 活见鬼,明明删除了数据,空间却没减少!
- 原创 | Git仓库的提交记录乱成一团,怎么办?
- 原创 | 平面内有N个点,如何快速求出距离最近的点对?
- 原创 | codeforces 1426F,初学者也能做,div3的最难题
- 安全研究 | YARA规则阻止Windows事件日志记录