[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方法决定当前操作是否被授权访问。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Vamei实验室

Linux的“壳”

在上一篇文章中,我们已经初尝了Shell的好处。由于我们后面将大量借助Shell,所以在这里先简要介绍一下这件工具。 什么是Shell 我们已经说过,Shell...

2345
来自专栏Android群英传

Gradle函数复用的一点实践

1211
来自专栏coding

python的中异常处理处理ZeroDivisionError异常处理 FileNotFoundError 异常异常时保持静默

Python 使用被称为 异常 的特殊对象来管理程序执行期间发生的错误。每当发生让 Python 不知所措的错误时,它都会创建一个异常对象。如果你编写了处理该异...

2442
来自专栏数据库

Redis列表的“绝地反击”

大家晚上好,今天介绍Redis中的列表数据结构。 Redis中的列表是用来存储多个有序的字符串的,最神奇的地方是:竟然可以在列表两端插入(push)和弹出(po...

22510
来自专栏数据结构笔记

实战:简书爬取之多线程爬取(二)速度提升何止10倍

其次就是这样的代码往往会有很严重的竞争问题,需要很多的资源锁来保证线程安全,这样就拉低了程序执行的速度。

1732
来自专栏JAVA技术zhai

JVM虚拟机详解

  JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿...

1422
来自专栏唐郑望的专栏

Go 语言之三驾马车

Go 语言的三个核心设计: interface 、goroutine 、 channel。

1.8K0
来自专栏未闻Code

使用生成器把Kafka写入速度提高1000倍

通过本文你会知道Python里面什么时候用yield最合适。本文不会给你讲生成器是什么,所以你需要先了解Python的yield,再来看本文。

911
来自专栏進无尽的文章

设计模式| 行为型模式 (下)

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代器模式、解释器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式。分两篇文章...

1032
来自专栏个人随笔

房上的猫:JavaDoc注释

//这是一个注释 /*   *这是一个演示程序   */ /**    *@这是JavaDoc注释。   */ JavaDoc注释    背景:       j...

35710

扫码关注云+社区

领取腾讯云代金券