通常希望对一个给定的方法所授予的权限做一些微调。一般是通过限制给定代码片的运行权限而做到这一点。CLR提供了两种方式来达到这个目的。你可以将有效的权限限制为由策略所授予的权限的一个子集,也可以显式地拒绝一个或多个权限,这些动作都可以以声明式或强制式来达成,SecurityAction.PermitOnly和SecurityAction.Deny可以同一个Security
Attribute一起使用,以声明达到这个目的。例如,考虑如下代码:
using System.Net;
using System.Security.Permissions;
pulic sealed class Utils{
[DnsPermission(SecurityAction.PermitOnly,Unrestrictedc=true)]
public static IPAddress LookupHost(string host){
return Dns.GetHostByname(host).AddressList[0];
}
}
这个使用声明式安全的示例等价于下面这个使用的强制式全安的示例:
using System.Net;
using Sysetm.Security.Permissions;
public sealed class Utils{
public static IPAddress LookupHost(string host){
DnsPermission perm=new DnsPermission(PermissionState.Unrestricted);
perm.PermitOnly();
return Dns.GetHostByName(host).AddressList[0];
}
}
在这两个示例中,假如DnsGetHostByName方法要求任何DnsPermission的权限,该要求都将被拒绝,即使LookupHost方法(以及它的所有调用方)实际上已经被授予策略所请求的权限了。假如LookupHost只想拒绝某个特定权限的话,下面代码即可满足需要:
using System.Net;
using Sysetm.Security.Permissions;
public sealed class Utils{
[FileIOPermission(SecurityAction.Deny.Unrestricted=true]
public static IPAddress LookupHost(string host){
return Dns.GetHostByName(host).AddressList[0];
}
}
}
下面是等价的强制式代码:
using System.Net;
using Sysetm.Security.Permissions;
public sealed class Utils{
public static IPAddress LookupHost(string host){
FileIOPermission perm=new FileIOPermission(PermissionState.Unrestricted);
perm.Deny();
return Dns.GetHostByName(host).AddressList[0];
}
}
}
在这种情况下,列于Dns.GetHostByName中的FileIOPermission的任何要求都将被拒绝,不过,所有其他权限类型都将服从于策略而发挥作用。注意,这一点很重要,对于一个给定的堆栈框架来说,只能有一个权限集可以在适当位置使用Deny或PermitOnly。例如,考虑如下方法:
using System.Net;
using Sysetm.Security.Permissions;
public sealed class Utils{
public static IPAddress LookupHost(string host){
FileIOPermission p1=new FileIOPermission(PermissionState.Unrestricted);
RegistryPermission p2=new RegistryPermission(PermissionState.Unrestricted);
p1.Deny();
p2.Deny();
return Dns.GetHostByName(host).AddressList[0];
}
}
在这个示例中,对Deny的第二次调用将会导致一个异常被抛出,因为在某个地方已经调用了Deny。为了将这个两个权限都禁止掉,需要像下面所展示的示例那样,使用一个权限集:
using System.Net;
using Sysetm.Security.Permissions;
public sealed class Utils{
public static IPAddress LookupHost(string host){
FileIOPermission p1=new FileIOPermission(PermissionState.Unrestricted);
RegistryPermission p2=new RegistryPermission(PermissionState.Unrestricted);
PermissionSet ps=new PermissionSet(null);
ps.AddPermission(p1);
ps.AddPermission(p2);
ps.Deny();
return Dns.GetHostByName(host).AddressList[0];
}
}
如此一来,两个权限都将被Dns.GetHostByName所拒绝。
受信任的组件经常需要它们的调用方具有可能还没有被授予的权限,例如,System.Net.Dns类型需要调用底层的gethostbyname API函数。像所有的API调用一样 它会导致CLR要求SecurityPermissionFlags.UnmanagedCode权限。然而,要求所有调用方都要有这样的权艰,将会使得Dns类型除了对于最受信任的组件有用外,对于别人没有什么用,为了解决这个问题,CLR支持Assert(断言)安全动作。
当一个给定的安全权限由一个方法断言时,对那个权限的任何要求都将会终止对该方法框架堆栈的遍历。如图9.8所示,通过断言一个权限,你就指明了调用方的权限将不予考虑。有趣的是,断言一个权限的动作的本身就是一个被保护的操作,需要断言方法拥有一个SecurityPermissionFlag.Assertion权限。一般来说,要求断言一个权限的方法(Methods)和调用方可能拥有的较少权限相呼应。例如,DnS.GetHosByName方法可能带有如下安全特性。
using System.Net;
using Sysetm.Security.Permissions;
namespace System.Net{
public sealed class Dns{
[DnsPermission(SecurityAction.Demand,Unrestricted=true),
SecurityPermission(SecurityAction.Assert,Flags=SecurityPermissionFlag.UnmanagedCode)]
public static IPHostEntry GetHostByName(string host){
//如果我们到了这里,该要求和断言就被满足了!
}
}
}
注意,这一点很重要,即,只有在发出请求的方法被授予了正被断言的权限时,断言才会成功,你不能使用断言去获取还没有授予该方法的权限。.