[.NET 基于角色安全性验证] 之一:ASP.NET Forms 基础

本文介绍.NET框架下基于角色的安全性验证原理及实现方式,包括主体(Principal)和标识(Identity)对象的概念,以及如何使用WindowsPrincipal/WindowsIdentity进行权限验证。

.NET 基于角色安全性验证的核心是主体(Principal)和标识(Identity)对象,其中主体负责角色或者组的验证,标识对象封装有关正在验证的用户或实体的信息。角色安全性验证通过生成可供当前线程使用的主体信息来支持授权,其中主体用关联的标识进行构造。

public interface IPrincipal
{
// Methods
bool IsInRole(string role);

// Properties
IIdentity Identity { get; }
}

public interface IIdentity
{
// Properties
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}


在 .NET Framework 中提供了两组 Principal/Identity 类型,分别是基于 Windows 操作系统账户的 WindowsPrincipal/WindowsIdentity,以及用来进行自定义验证的 GenericPrincipal/GenericIdentity。

主体(Principal)对象在应用程序域(AppDomain)中绑定到调用上下文(CallContext)对象,缺省情况下,应用程序域会自动创建采取默认安全策略的 GenericPrincipal/GenericIdentity对象,同时主体(Principal)对象引用从创建线程自动复制到新线程的调用上下文(CallContext)中。我们可以通过 Thread.CurrentPrincipal 获得缺省主体(Principal)和标识(Identity)对象信息。

Console.WriteLine(Thread.CurrentPrincipal);
Console.WriteLine(Thread.CurrentPrincipal.Identity);


接下来,我们使用 WindowsPrincipal/WindowsIdentity 做一些简单的验证,同时为了进一步理解基于角色安全性验证的用途。

static void Test()
{
   Console.WriteLine("Test...");
}

static void Main(string[] args)
{
   Test();
}


我们修改上面这段代码,要求 Test() 方法必须是拥有管理员权限才能调用。

1. 我们使用 System.Security.Permissions.PrincipalPermissionAttribute 特性为 Test 方法加上角色验证标记,要求调用用户(Windows 操作系统登录用户)必须是 "Administrators" 组成员。

2. 在 Main 方法中设置线程的主体和标识对象。WindowsIdentity.GetCurrent() 用来获取当前登录用户的标识对象,如果登录用户属于 Adminstrators 组,则 Test() 方法正常调用,否则会触发 SecurityException 异常(我们可以使用 WindowsIdentity.GetAnonymous() 获取匿名用户标识对象来触发该异常)。

[PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
static void Test()
{
   Console.WriteLine("Test...");
}

static void Main(string[] args)
{
   Thread.CurrentPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
   Test();
}


我们还可以使用其他的方法来做到这一点。

1. 使用 PrincipalPermission 对象替换 PrincipalPermissionAttribute,我们就可以使用动态权限验证,可以将用户名或者角色参数写入配置文件中。
2. 使用 AppDomain.CurrentDomain.SetThreadPrincipal 设置主体对象和 Thread.CurrentPrincipal 作用相同。我们还可以直接使用 AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal) 让系统自动使用当前登录用户名创建 WindowsPrincipal/WindowsIdentity。

static void Test()
{
   new PrincipalPermission(null, "Administrators").Demand();
   Console.WriteLine("Test...");
}

static void Main(string[] args)
{
   AppDomain.CurrentDomain.SetThreadPrincipal(new WindowsPrincipal(WindowsIdentity.GetCurrent()));
   Test();
}


或者

static void Test()
{
   new PrincipalPermission(null, "Administrators").Demand();
   Console.WriteLine("Test...");
}

static void Main(string[] args)
{
   AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
   Test();
}


上面的例子都是基于角色或者组的验证,当然我们还可以基于用户进行验证。

[PrincipalPermission(SecurityAction.Demand, Name="YUHEN//q.yuhen")]
new PrincipalPermission("YUHEN//q.yuhen", null).Demand();


当然,我们还可以同时用 role 和 name。PrincipalPermission 对象比 PrincipalPermissionAttribute 更加灵活,我们可以使用它进行多个权限的并集运算,以及进行 xml 转换等。

下面是使用 GenericPrincipal/GenericIdentity 改写的代码。

//[PrincipalPermission(SecurityAction.Demand, Name="q.yuhen", Role="admins")]
static void Test()
{
   new PrincipalPermission(null, "Administrators").Demand();
   Console.WriteLine("Test...");
}

static void Main(string[] args)
{
   // 创建自定义用户标识对象。
   GenericIdentity identity = new GenericIdentity("q.yuhen");
  
   // 创建主体对象,并指定所拥有的角色数组。
   string[] roles = new string[] { "admins" };
   GenericPrincipal principal = new GenericPrincipal(identity, roles);
  
   // 设定主体。
   AppDomain.CurrentDomain.SetThreadPrincipal(principal);
  
   Test();
}


除了使用上述方法外,某些时候我们并不希望触发 SecurityException 异常,我们希望能给出另外的执行策略,那么可以直接使用 Principal.InRole 以及 Identity.Name 了。

static void Test()
{
   if (Thread.CurrentPrincipal.IsInRole("admins") && Thread.CurrentPrincipal.Identity.Name == "q.yuhen")
   {
     Console.WriteLine("Test...");
   }
   else
   {
     Console.WriteLine("您没有执行权限!");
   }
}


总结一下,基于角色的安全检查有三种方法。

1. 使用命令式安全检查。该方法主要是通过 PrincipalPermission.Demand() 方法进行。
2. 使用声明性安全检查。通过 PrincipalPermissionAttribute 特性指定运行所需角色和用户名。
3. 直接访问 Principal 对象。访问 Thread.CurrentPrincipal 属性获得当前主体和标识对象,并调用其相关方法和属性进行进一步验证。

有关细节可参考 MSDN 文档,角色验证主要用于 ASP.NET 环境,雨痕将在后续 Blog 中做进一步说明。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值