日期:2012-01-14  浏览次数:20487 次

在基于 .NET 的应用程序中使用基于角色的安全设置


.NET Framework 在 System.Security.Principal 命名空间中提供了基于角色的安全设置实现,您可以用此实现来授权应用程序。要在 .NET Framework 中使用应用程序授权,请创建 IIdentityIPrincipal 对象来表示用户。IIdentity 封装的是一个通过验证的用户,IPrincipal 则是用户标识和用户角色的组合。
图 4 显示了 IIdentityIPrincipal 对象之间的关系。

图 4:IIdentity 和 IPrincipal 对象之间的关系
请注意图 4 中的以下几点:
  1. IIdentity 对象是实现 IIdentity 类的实例。IIdentity 对象表示特定的用户。
  2. IIdentity 接口具有 NameIsAuthenticatedAuthenticationType 属性。实现 IIdentity 的类通常还包含有特定用途的其他私有成员,例如,WindowsIdentity 类封装了正运行代码的用户的帐户令牌。
  3. IPrincipal 对象是实现 IPrincipal 的类的实例。IPrincipal 对象是代表用户的 IIdentity 及其具有的角色的组合。这样就可以实现单独的身份验证和授权。
  4. IPrincipal 对象使用 IsInRole 方法执行授权,并通过 Identity属性提供对 IIdentity 对象的访问。

使用标识


.NET Framework 提供了四种实现 IIdentity 接口的类:
  • WindowsIdentity
  • GenericIdentity
  • PassportIdentity
  • FormsIdentity

每种类都允许您使用不同种类的用户标识。要访问使用 Windows 身份验证的应用程序的当前 WindowsIdentity 对象,可以使用 WindowsIdentity 类的静态 GetCurrent 方法,如以下代码所示:
您还可以通过在自己定义的类中实现 IIdentity 接口来创建自定义标识类。有关创建自定义标识的详细信息,请参阅本指南后面的扩展默认实现。有关如何使用默认 IIdentity 实现的详细信息,请参阅本指南后面的设计用于授权的身份验证。

使用主体


.NET Framework 提供了链接用户角色和标识的 IPrincipal 接口。所有执行应用程序授权的托管代码都应该使用实现 IPrincipal 的类的对象。例如,WindowsPrincipalGenericPrincipal 类提供了内置的 IPrincipal 实现。另外,您也可以根据 IPrincipal 创建自己的自定义主体类。
为了提高编码效率,您可以使用本指南的设计用于授权的身份验证一节中介绍的技术,通过使用 Thread 对象的静态 CurrentPrincipal 属性可以将 IPrincipal 对象链接到线程,这样当前线程就可以轻松地访问 IPrincipal 对象了,如以下代码所示:
然后,您可以测试用户是否属于某一特定的角色,从而执行授权检查。为此,可以使用 IPrincipal 接口的 IsInRole 方法,如以下代码所示:
ASP.NET 应用程序处理 IPrincipal 对象的方法与其他基于 .NET 的应用程序的处理方法有所不同。ASP.NET 通过无状态的 HTTP 协议创建会话外观。作为会话的一部分,执行用户请求的所有代码可以通过 HttpContext 对象的 User 属性,使用代表用户的 IPrincipal 对象。Global.asax 文件发生 OnAuthenticate 事件之后,公共语言运库使用 HttpContext.User 值自动更新 Thread.CurrentPrincipal
ASP.NET 应用程序通常使用 User 属性执行授权检查,如以下代码所示:
注意:手动更改 HttpContext.User 将自动更新在同一 HTTP 上下文环境中执行的所有线程的 Thread.CurrentPrincipal。但是,改变 Thread.CurrentPrincipal 不会影响 HttpContext.User 属性,它只影响为请求中其余内容选择的线程。

有关创建自己的 IPrincipal 类型的详细信息,请参阅本指南后面的扩展默认实现。有关如何使用默认 IPrincipal 实现的详细信息,请参阅本指南后面的设计用于授权的身份验证。

授予使用 IIdentity 和 IPrincipal 对象的权限


使用 IIdentity 对象是一种敏感操作,因为在该操作中可以使用与用户相关的信息。允许应用程序更改当前的 IPrincipal 对象也应该受到保护,因为应用程序授权能力是以当前的主体为基础的。框架要求这些操作具有代码访问安全性权限,从而提供了保护。使用 Caspol.exe 或 .NET Framework 配置工具为需要管理这些对象的应用程序授予 SecurityPermissionAttribute.ControlPrincipal 权限。
默认情况下,所有本地安装的应用程序均具有该权限,因为它们是在“完全信任”的权限设置下运行的。
执行以下方法需要 ControlPrincipal 权限:
  • AppDomain.SetThreadPrincipalPolicy()
  • WindowsIdentity.GetCurrent()
  • WindowsIdentity.Impersonate()
  • Thread.CurrentPrincipal()

有关使用 CASPOL 设置安全权限的详细信息,请参阅 MSDN Library 中的 Configuring Security Policy Using the Code Access Security Policy Tool (Caspol.exe)(英文)。

Windows 和公共语言运库之间管理授权的区别


公共语言运库在 Windows 安全结构之上有一个单独的安全结构。Windows 线程具有 Windows 授权用户的令牌,而运行时线程具有代表该用户的 IPrincipal 对象。
因此,在开发代码时,必须至少考虑两种代表用户的安全上下文。例如,设想一个使用窗体身份验证的 ASP.NET 应用程序:默认情况下,ASP.NET 进程在名为“ASPNET”的 Windows 服务帐户(专为应用程序创建的用户帐号)下运行。假设有一位名为 Bill 的用户登录到 Web 站点。Thread.CurrentPrincipal 属性代表窗体身份验证的用户 Bill。公共语言运库看到以 Bill 运行的线程,于是所有托管代码都将 Bill 看作主体。如果托管代码要求访问系统资源(如文件),则不管 Thread.CurrentPrincipal 的值如何,非托管代码都可以看到 ASPNET Windows 服务帐户。图 5 说明了公共语言运库和操作系统线程之间的授权关系。

图 5:公