试一下下面的代码,我们之前没有使用security命名空间,但是我们现在来用用看。
using System.Security.Permissions;
添加另一个button到已经存在的form上。
{
try
{
InitUI( 1 );
}
catch (SecurityException err)
{
MessageBox.Show(err.Message, " Security Error " );
}
catch (Exception err)
{
MessageBox.Show(err.Message, " Error " );
}
}
InitUI
只是调用ShowUI函数。记住它已经被拒绝了对c盘的读操作。
// Note: Using declrative syntax
[FileIOPermission(SecurityAction.Deny,Read = " C:\\ " )]
private void InitUI( int uino)
{
// Do some initializations
ShowUI(uino); // call ShowUI
}
ShowUI
函数得到uino显示适当的UI。
{
switch (uino)
{
case 1 : // That's our FileRead UI
ShowFileReadUI();
break ;
case 2 :
// Show someother UI
break ;
}
}
ShowFileReadUI
显示与读文件有关的UI。
{
MessageBox.Show( " Before calling demand " );
FileIOPermission myPerm = new
FileIOPermission(FileIOPermissionAccess.Read, " C:\\ " );
myPerm.Demand();
// All callers must have read permission to C: drive
// Note: Using imperative syntax
// code to show UI
MessageBox.Show( " Showing FileRead UI " );
// This is excuted if only the Demand is successful.
}
我知道这是一个槽糕的例子,但是它已经足够了。
现在运行我们的代码。你会得到一个“Before calling demand”的消息,然后跳出一个自定义的错误对话框“security error”。哪里错了呢?看下面的图片:
【图11】
我们已经禁止了InitUI
方法的
读的权限。所以当ShowFileReadUI
请求对c盘的写的权限的时候,它检查堆栈的时候找到不是每个调用者都被允许这个demanded permission,显示一个异常。只需要注释在InitUI方法里面注释Deny
statement, 它就可以工作了,因为所有的调用者都有demanded的permission。
注意,根据文档,许多.NET Framework的类已经有了demands关联它。例如StreamReader
,StreamReader自动需要FileIOPermission
.所以用其他demand去替换它会导致一个堆栈的错误。
Link Demand
一个link demand只检查你的代码的直接调用者。那意味者它不会对堆栈起作用。当你的代码跳到一个典型的引用,包括函数指针引用和方法调用会发生link。一个link demand只能用申明的方式。
private void MyMethod()
{
// Do Something
}
Inheritance Demand
Inheritance Demand能过被类和方法应用。如果它用到一个类上,所有从它继承的类都具有它的permission
private class MyClass()
{
// what ever
}
如果它用到一个方法上,所有继承它的类必须制定permission去重写那个方法。
{
public class MyClass() {}
[SecurityPermission(SecurityAction.InheritanceDemand)]
public virtual void MyMethod()
{
// Do something
}
}
就像link demand,inheritance demand也只能用声明的方式。
Requesting Permissions
想象一个场景。你给一个用户一个form其中包含有20多个field去填充,所有的信息必须保存在一个text文件中,用户填充了所有的信息,当他要保存的时候,他得到了一个信息,他没有足够的权限去创建一个文件。当然你可以试图沉静的告诉他为什么会发生这个,因为我们调用堆栈的时候...因为一个demand。。如果你足够幸运,你可以从microsoft那得到这个警示(相信我...有时他确实会发生)。
你在装载装配的时候请求permission的优先级是否比较容易呢?这里有3种方法去做他在CAS中。
- RequestMinimum
- RequestOptional
- RequestRefuse
注意这些只能用声明的语法应用在装配的级别,而不是应用给方法或者是类。最棒的是管理员可以在装配之后查看请求的permissions,使用permview.exe你可以查看它所被赋予的permissions
RequestMinimum
你可以使用requestMinimum去指定permissions。代码只允许在所有permissions都被赋予的时候才能够跑。在下面的代码片段中,有一个请求去写注册表的请求。如果这个没有被安全机制赋予权限,这个装配甚至不会被装载。就像之前提到的,这种请求能够在装载的时候完成。
using System.Windows.Forms;
using System.IO;
using System.Security;
using System.Security.Permissions;
// placed in assembly level
// using declarative syntax
[assembly:RegistryPermission(SecurityAction.RequestMinimum,
Write = " HKEY_LOCAL_MACHINE\\Software " )]
namespace SecurityApp
{
// Rest of the implementation
}
RequestOptional
使用RequestOptional,你能指定你的代码所需要的permissions,而不是跑的时候才请求。如果你的代码没有被赋予optional permissions,你必须处理代码片段在执行时需要optional permissions而抛出的异常。这里有一些在使用requestOptional时必须注意的事情
如果你使用RequestOptional和RequestMinimum,除了他们两再没有其他的permissions将被赋予,如果被安全机制所允许。尽管安全机制允许添加permissions到你的装配集,他们将不会被赋予。看下面的代码片段:
[assembly:FileIOPermission(SecurityAction.RequestMinimum, Read="C:\\")]
[assembly:FileIOPermission(SecurityAction.RequestOptional, Write="C:\\")]
这个装配集的permissions只是对文件系统的读和写。是否还需要显示UI?然后这个装配集被装载,但是一个异常被抛出,当显示UI的代码被执行的时候,因为尽管安全机制允许UIPermission
,但是它没有被装配集允许。
RequestRefuse
你可以使用RequestRefuse去指定你确定不需要被赋予的permissions在你的代码中,即使他们已经被安全机制赋予了,然后拒绝写的permission将保证你的代码不会被滥用
[assembly:FileIOPermission(SecurityAction.RequestRefuse, Write="C:\\")]