试一下下面的代码,我们之前没有使用 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:\\"
)]