65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 3.5 自定义 Windows 身份验证,使用 VB.NET – 案例研究

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.83/5 (3投票s)

2009年9月17日

CPOL

9分钟阅读

viewsIcon

63631

一个案例研究,展示了在 ASP.NET 3.5 中使用 VB.NET 实现 Windows 身份验证和自定义基于角色的授权。

1. 引言

本文基于 ASP.NET 3.5 和 VB.NET。应用程序安全在信息管理中扮演着重要角色。在正确的时间将正确的信息分发给正确的人是信息管理的关键。除了确保信息传达给正确的人之外,还必须确保信息永远不会落入未经授权的人手中。这就是信息安全的作用。提供应用程序安全是确保信息安全的重要方面。应用程序安全的主要目的是保护应用程序和数据免受未经授权的访问。

本案例研究的目的是解释如何使用“集成 Windows 身份验证”为 ASP.NET Web 应用程序实现应用程序安全。

2. 如何保护 Web 应用程序

身份验证和授权是确保应用程序安全的两个因素。

2.1. 身份验证

身份验证是决定谁可以访问应用程序的过程。用户名和密码身份验证最常见的机制。

2.2. 授权

授权是决定已验证用户可以使用应用程序执行什么操作的过程。应用程序可以为不同用户的访问提供不同的功能。对各种功能的访问可以根据用户类型进行限制。这称为基于角色的授权。例如,“管理员”将拥有比“访客用户”更多的访问权限。

3. 什么是“集成 Windows 身份验证”?

在集成 Windows 身份验证中,应用程序利用 Windows 用户的凭据。IIS 将客户端凭据提供给 ASP.NET。根据应用程序特定的安全架构,应用程序可以根据为应用程序配置的“访问权限信息”验证这些凭据。只有验证成功,用户才被允许访问应用程序。

Sample screenshot

3.1. 单点登录

这项技术允许用户使用相同的凭据访问多个应用程序。用户成功登录操作系统后,其他应用程序可以利用操作系统中的这些凭据。“单点登录”可以通过使用“集成 Windows 身份验证”在 ASP.NET 应用程序中实现。一旦用户登录 Windows 操作系统,他/她就可以自由访问应用程序,就像不需要再次登录一样(前提是用户已被授予访问应用程序的权限)。但是,在应用程序启动期间,它会悄悄地根据为应用程序配置的“访问权限信息”检查用户的凭据。只有当凭据匹配时,用户才被允许访问应用程序。

4. “Windows 身份验证”适用于何处?

由于“Windows 身份验证”使用 Windows 用户的凭据,因此它只能用于内部网应用程序。在内部网应用程序中,管理员对网络用户拥有完全控制权。应用程序可以设计成能够显示所有“Active Directory”用户,以便应用程序管理员可以配置被授权访问应用程序的用户。集成 Windows 身份验证最适合内部网环境,其中用户和 Web 服务器计算机位于同一域中,并且管理员可以确保每个用户都安装了 Microsoft Internet Explorer 2.0 或更高版本。

5. Windows 身份验证和授权方案

使用“WindowsAuthenticationModule”提供程序,可以以最少的 ASP.NET 编码提供 Web 应用程序安全。提供程序模块构造一个 WindowsIdentity 对象。默认实现构造一个 WindowsPrincipal 对象并将其附加到应用程序上下文。WindowsPrincipal 对象将身份映射到 Windows 组。使用 web.config 文件的授权标签,可以限制用户/组访问各种应用程序文件夹。

还可以实现自定义的 Windows 授权方案。为此,您可以使用“WindowsAuthentication_OnAuthenticate”事件处理程序从 WindowsIdentity 对象创建 WindowsPrincipal GenericPrincipal 对象。然后,您可以使用其中一个新对象来实现自己的自定义身份验证方案。

6. “Windows 身份验证”如何工作 - 案例研究

这是一个案例研究,展示了如何在 ASP.NET 中实现 Windows 身份验证和基于角色的安全性。它首先详细定义问题,然后是解决方案架构。它还详细介绍了解决方案实现的步骤。

6.1. 问题定义

这是一个为跨国公司 ABC 准备商业计划的 Web 应用程序。所有用户都已在其内部网域的 Active Directory 中注册,并且需要从该内部网访问应用程序。该应用程序为用户提供以下功能:

  1. 准备主数据
  2. 创建商业计划
  3. 批准或拒绝计划
  4. 准备报告

主数据 (MD) 用户的访问权限应严格限制为“准备主数据功能”,而中央支持团队 (CST) 可以访问除“批准或拒绝计划”之外的所有功能。区域经理 (AM) 只能访问“批准或拒绝计划”和“准备报告”。根据此要求,我们需要为该应用程序实现基于角色、单点登录的安全性。

6.2. 解决方案架构

我们可以使用“Windows 身份验证”为该应用程序提供基于角色、单点登录的安全性。为了启用 Windows 身份验证,我们需要将 IIS 目录设置配置为“集成 Windows 身份验证”。这将使 IIS 能够获取客户端凭据并将其传递给 ASP.NET 应用程序。

在本案例研究中,我们使用自定义 Windows 授权。使用“WindowsAuthentication_OnAuthenticate”事件处理程序,我们从 WindowsIdentity 对象创建了一个 GenericPrincipal 对象。选择自定义授权的原因如下:

  1. 应用程序角色与 Windows 组无关,并且
  2. 应用程序文件并未根据角色进行物理分组

应用程序还需要一些额外的“管理”屏幕来管理用户角色和身份验证信息。用户屏幕应显示“Active Directory”中的所有用户名,以便管理员可以只选择需要访问应用程序的用户。此屏幕还应允许管理员为用户分配以下三个角色中的任何一个——“MD”、“CST”或“AM”。此信息存储在数据库中单独的“用户”表中。

在会话启动时,应用程序必须根据数据库中存储的客户端凭据检查 IIS 发送的客户端凭据。如果找不到匹配项,则必须报告未经授权的访问尝试并退出应用程序。如果客户端凭据匹配,则会构建一个客户端 cookie,其中存储用户凭据和角色信息。对于后续请求,应用程序不访问数据库验证客户端凭据,而是使用此客户端 cookie。为了保护客户端 cookie,我们使用“用户身份”和“角色”信息创建了一个“FormsAuthenticationTicket”。然后将此“FormsAuthenticationTicket”作为参数传递给“FormsAuthentication”类的“Encrypt”方法,以获取“FormsAuthenticationTicket”的加密字符串。此字符串随后存储在客户端 cookie 中中。

在每个请求中,如果用户已通过身份验证,应用程序将创建一个安全“Principal”对象,并将用户角色信息存储在其中。然后将此“Principal”对象放入 HttpContext.Current.User。在每个“Page_Load”事件中,应用程序可以从 HttpContext.Current.User 访问“Principal”对象,并验证用户角色是否被授权访问该页面。

6.3. 实现细节

6.3.1. 配置应用程序的 IIS 安全设置

在应用程序的 IIS 安全设置中,选中“集成 Windows 身份验证”,并取消选中所有其他选项。

6.3.2. 用于 Windows 身份验证的 Web.Config 条目

Web.config 中,在 System.Web 标签下,放入以下条目:

<authenticationmode="Windows"/>
<authorization>
< allow users ="*" /> 
</authorization> 

如果您希望子进程(例如:Web 服务)也使用主线程的相同凭据,请使用以下条目。

<identityimpersonate="true"/>

6.3.3. 用户管理屏幕

如“解决方案架构”部分所述,应用程序应该具有“用户管理”屏幕。使用此屏幕,管理员可以将 AD 用户名映射到应用程序角色。在此应用程序中,用户角色是预定义的硬编码值——“MD”、“CST”和“AM”。应用程序管理员可以直接键入 AD 用户名,或者应用程序可以显示所有 AD 用户名,以便管理员可以选择用户名。为了显示 AD 用户名,应用程序可以使用 .NET 基类 System.DirectoryServices 查询 Windows Active Directory。

6.3.4. 安全主体对象

创建一个实现 System.Security.Principal.IPrincipal 接口的类。

Imports System
Imports System.Security.Principal
Public Class myAppPrincipal
Implements IPrincipal
Private m_identity As IIdentity
Private m_roles As String()
Private m_userId As String

Public Sub New(ByVal identity As IIdentity, ByVal roles As String())
m_identity = identity
ReDim m_roles(roles.Length)
roles.CopyTo(m_roles, 0)
Array.Sort(m_roles)
m_userId = identity.Name
End Sub
Public Property UserId() As String
Get
Return m_userId
End Get
Set(ByVal value As String)
m_userId = value
End Set
End Property

Public ReadOnly Property Identity() As System.Security.Principal.IIdentity _
	Implements System.Security.Principal.IPrincipal.Identity
Get
Return m_identity
End Get
End Property

Public Function IsInRole(ByVal role As String) As Boolean _
	Implements System.Security.Principal.IPrincipal.IsInRole
Return IIf(Array.BinarySearch(m_roles, role) >= 0, True, False)
End Function
End Class

6.3.5. 检查身份验证和识别角色

实现安全最重要的部分是确保在每个请求中,应用程序验证身份并解析用户角色。为此,我们利用以下全局应用程序级事件。

  1. WindowsAuthentication_OnAuthenticate(Object source, WindowsAuthenticationEventArgs e)
  2. Application_AuthenticateRequest(Object sender, EventArgs e)

这些事件在每个请求时自动引发。

WindowsAuthentication_OnAuthenticate”首先被引发。在相应的方法中,我们实现以下逻辑。

  1. 检查应用程序是否存在“authenticationCookie”。如果存在,则从方法返回。如果不存在,则继续执行下一步。
  2. 提取 IIS 发送的 AD 用户名。它在事件参数中可用作“e.Identity.Name”。
  3. 根据此用户名查询数据库以获取应用程序角色。
  4. 创建一个“FormsAuthentication ticket”并嵌入用户角色字符串。
  5. 创建一个新的“applicationauthenticationCookie”并将加密的“FormsAuthentication ticket”存储在其中。

在“Application_AuthenticateRequest”事件的方法内部,执行以下操作。

  1. 读取“applicationauthenticationCookie”并重新创建“FormsAuthentication ticket”。
  2. 从“FormsAuthentication ticket”中读取用户角色,并创建一个包含这些用户角色的“主体对象”。
  3. 将此“主体对象”存储在“HttpContext.Current.User”中。

以下代码显示了这些任务的实现

Public Sub WindowsAuthentication_OnAuthenticate(ByVal sender As Object, _
	ByVal args As WindowsAuthenticationEventArgs)
If (Not Request.Cookies.Get("authCookie") Is Nothing) Then
Exit Sub
End If
Dim strUserIdentity As String
Dim strUserRoles As String
Dim formsAuthTicket As FormsAuthenticationTicket
Dim httpCook As HttpCookie
Dim strEncryptedTicket As String
strUserIdentity = args.Identity.Name
strUserRoles = GetUserRoles(strUserIdentity)' // "MD|CST|AM" from DB
formsAuthTicket = New FormsAuthenticationTicket(1, strUserIdentity, DateTime.Now, _
DateTime.Now.AddMinutes(60), False, strUserRoles)
strEncryptedTicket = FormsAuthentication.Encrypt(formsAuthTicket)
httpCook = New HttpCookie("authCookie", strEncryptedTicket)
Response.Cookies.Add(httpCook)
End Sub
Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
' Fires upon attempting to authenticate the use
Dim formsAuthTicket As FormsAuthenticationTicket
Dim httpCook As HttpCookie
Dim objGenericIdentity As GenericIdentity
Dim objMyAppPrincipal As myAppPrincipal
Dim strRoles As String()
httpCook = Context.Request.Cookies.Get("authCookie")
formsAuthTicket = FormsAuthentication.Decrypt(httpCook.Value)
objGenericIdentity = New GenericIdentity(formsAuthTicket.Name)
strRoles = formsAuthTicket.UserData.Split("|")
objMyAppPrincipal = New myAppPrincipal(objGenericIdentity, strRoles)
HttpContext.Current.User = objMyAppPrincipal
End Sub

6.3.6. 检查基于角色的授权

在每个网页的“Page_Load”中,检查“HttpContext.Current.User”中当前用户角色是否被允许访问该页面。如果不允许,则重定向到公共页面,显示消息“您无权查看此页面”。

7. 总结

  • 提供应用程序安全是确保信息安全的重要方面。
  • 身份验证有助于验证用户是否确实是其声称的身份。应用程序从用户那里获取凭据(各种形式的身份识别,例如姓名和密码),并根据某个权限验证这些凭据。如果凭据有效,则提交凭据的实体被视为经过身份验证的身份。授权通过授予或拒绝经过身份验证的身份特定权限来限制访问权限。
  • ASP.NET 将 Windows 身份验证与 Microsoft Internet Information Services (IIS) 身份验证结合使用。当 IIS 身份验证完成时,ASP.NET 使用经过身份验证的身份来授权访问。
  • 在 ASP.NET 中,Windows 身份验证可以与“Windows 角色”基于授权或“自定义授权”结合使用。在“Windows 角色”基于授权中,根据 web.config 中的设置,授予/拒绝 Windows 用户/组对应用程序文件夹的访问权限。而在“自定义授权”中,此逻辑以编程方式实现。

8. 缩写

缩写 展开
AD Active Directory
IIS Internet 信息服务
MD 主数据
CST 中央支持团队
AM 区域经理

9. 参考文献

© . All rights reserved.