Windows用户组安全主体权限模式,顾名思义,就是将利用Windows安全系统将对应的Windows帐号所在的用户组作为该用户权限集的授权方式。认证和授权密不可分,但是对于认证和授权在WCF安全体系中的实现来说,它们则是相对独立的。认证属于安全传输的范畴,是在信道层实现的,而授权则是在服务模型层实现的。但是对于基于Windows用户组的授权来说,最终体现出来的授权行为却和采用何种认证具有密切的关系。
一、Windows用户组授权与认证的关系
无论是对于基于Windows用户组还是基于ASP.NET Roles提供程序的授权,最终都体现在创建相应的安全主体,并将其附加到当前线程上。对于Windows用户组模式来说,有一点是肯定的:不论采用何种客户端凭证类型以及认证模式,最终建立的安全主体都是一个WindowsPrincipal,并且这个WindowsPrincipal对应的安全身份是一个WindowsIdentity。但是该WindowsPrincipal的Identity能否正确地反映被认证后的用户,以及其本身能够正确反映该认证用户的权限,就和认证有密切的关系。
具体来说,当你选择了Windows用户组安全主体权限模式,只有在采用Windows认证的情况下最终生成的安全主体才能正确地反映被认证的用户。这里的Windows认证包括如下三种情况:
- 客户端凭证为Windows凭证;
- 客户端凭证为用户名/密码凭证,并采用Windows认证模式;
- 客户端凭证为X.509证书凭证,并允许与Windows帐号进行映射。
在其他情况下,最终被创建的是一个“空”的WindowsPrincipal。这个空的WindowsPrincipal不仅仅体现在具有一个“空”的权限集,而且其内部的WindowsIdentity也为“空”。该WindowsIdentity具有如下面列表所示的属性。
- Name:空字符串
- AuthenticationType: 空字符串
- IsAuthenticated:False
- Groups:Null
- IsAnonymous:True
- IsGuest:False
- IsSystem:False
在非Windows认证的情况下,即使存在着一个与认证用户一致的Windows帐号,WCF授权系统都不会基于该Windows帐号来创建最终的WindowsPrincipal。举个例子,假设服务寄宿端所在的域中具有一个用户叫做“张三”,并且存在于当前机器的管理员(Administrators)用户组中。现在我们对某个服务操作进行授权,要求必须在具有管理员权限才能被调用。在进行服务寄宿的时候,终结点的绑定采用用户名/密码作为客户端凭证,并选择Membership认证模式。在认证成功的情况下,被授权的服务操作也是不能被正常调用的。
通过前面一篇文章的介绍,我们知道了WCF采用怎样的授权的方式通过ServiceAuthorizationBehavior这一服务行为来控制。所以针对授权的编程主要就体现在对该服务行为的设置。对于Windows用户组授权来说,我们只需要将ServiceAuthorizationBehavior的PrincipalPermissionMode属性设置成PrincipalPermissionMode.UseWindowsGroups即可。
二、ServiceAuthorizationBehavior服务行为的设置
既然ServiceAuthorizationBehavior是一个服务行为,我们只需要通过编程或者配置的方式将该服务行为添加到当前服务的行为列表中就可以了。你可以按照下面的编程方式让寄宿的服务采用基于Windows用户组授权模式。
1: using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
2: {
3: ServiceAuthorizationBehavior behavior = host.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
4: if (null == behavior)
5: {
6: behavior = new ServiceAuthorizationBehavior();
7: host.Description.Behaviors.Add(behavior);
8: }
9: behavior.PrincipalPermissionMode = PrincipalPermissionMode.UseWindowsGroups;
10: host.Open();
11: //...
12: }
此外在ServiceHost你也可以通过ServiceHost的只读属性Authorization得到这个ServiceAuthorizationBehavior对象。如下面的代码片断所示,该属性实际上是定义在ServiceHost的基类ServiceHostBase中。
1: public abstract class ServiceHostBase
2: {
3: //其他成员
4: public ServiceAuthorizationBehavior Authorization { get; }
5: }
在读取该属性的时候,如果当前服务描述中的服务行为列表中找不到ServiceAuthorizationBehavior,系统会自动创建一个ServiceAuthorizationBehavior对象并添加到服务行为列表中。所以对于上面的这段服务寄宿代码实际和下面是完全等效的。
1: using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
2: {
3: host.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.UseWindowsGroups;
4: host.Open();
5: //...
6: }
我们依然推荐采用配置的方式进行授权模式的设置。而下面一段配置和上面的代码在作用上是等效的。
1: <configuration>
2: <system.serviceModel>
3: <services>
4: <service name="Artech.WcfServices.Services.CalculatorService" behaviorConfiguration="UseWindowsGroupsAuthorization">
5: <endpoint address="http://127.0.0.1/calculatorservice" binding="ws2007HttpBinding" contract="Artech.WcfServices.Contracts.ICalculator"/>
6: </service>
7: </services>
8: <behaviors>
9: <serviceBehaviors>
10: <behavior name="UseWindowsGroupsAuthorization">
11: <serviceAuthorization principalPermissionMode="UseWindowsGroups"/>
12: </behavior>
13: </serviceBehaviors>
14: </behaviors>
15: </system.serviceModel>
16: </configuration>
为了让读者对基于Windows用户组的授权具有深刻的认识,在《下篇》中我们通过一个简单的事例来讲解在真正的应用中该授权模式如何使用。
[WCF权限控制]基于Windows用户组的授权方式[上篇]
[WCF权限控制]基于Windows用户组的授权方式[下篇]