ASP.NET Windows 验证 Part.2(实现)

       在 ASP.NET 应用程序中使用 Windows 验证并访问 ASP.NET 中的用户身份,需要执行 3 个步骤:

  1. 使用 IIS 管理器配置 Windows 验证的类型
  2. 通过 web.config 文件配置 ASP.NET 来使用 IIS 验证信息
  3. 限制匿名用户对某个网页、某个下级目录或整个应用程序的访问

       IIS 7.x 运行于 ASP.NET 整合模式,前两步被合成为了一步,因为 IIS 配置时,控制台会直接按要求配置应用程序的 web.config 文件。

配置 IIS 7.x

       运行 IIS 7.x 时,Windows 验证是在 HTTP 模块管道里以模块实现的。这个管道是 IIS 发布的原生模块以及 ASP.NET 发布的托管模块的混合。这带来的巨大优势是可以为 IIS 7.x 里配置的所有应用程序使用标准的 ASP.NET HTTP 模块,甚至那些不是基于 ASP.NET 的应用程序

       你可以通过 IIS 管理控制台完成所有的配置,如下图:

image_thumb[1]

       无论何时执行这个配置,IIS 7.x 都会更新程序的 web.config 文件,如果需要也会同时更新中央的 applicationHost.config 配置文件。

 

配置 ASP.NET

       一旦配置了 IIS,验证流程会自动发生。但是,如果你使用 VS 测试 Web 服务器且想访问 ASP.NET 应用程序中已验证用户的身份信息,就需要手动配置 web.config

<system.web>
  <authentication mode="Windows" />
</system.web>

       这将告诉 ASP.NET 你想使用 windows 验证模块。WindowsAuthenticationModule HTTP 模块将处理 AuthenticateRequest 事件,以便提取 Web 服务器验证的身份,这与 IIS 版本无关。

 

IIS 7.x 管道

       我们已经初步了解了配置的本质。但实际上,配置 IIS 7.x 使用基本验证或 Windows 验证,它实际所做的要比我们了解的多得多。看下图:

image_thumb[5]

       WindowsAuthenticationModule 是 IIS 7.x 原生 HTTP 模块,而 WindowsAuthentication 是由 ASP.NET 提供的托管模块。原生模块是 Web 服务器自身对验证协议的实现。对于 Basic 验证,它就是 BasicAuthenticationModule,这些模块负责处理原生验证协议。例如,对于 Windows 验证,模块负责处理 NTLM(询问/响应)或者 Kerberos(握手)。

       托管模块随 ASP.NET 发布。它负责从由原生模块验证的用户中析取出 Windows 用户信息,之后,Windows 用户信息就会对应用程序可用。

       也就是说,当我们通过 IIS7.x 配置 Windows、Basic、Digest 验证时,IIS 做了2件事,它首先配置 ASP.NET,其次要配置原生验证模块。原生模块或者在 Web 服务器的中央配置 applicationHost.config 里配置,或者在应用程序的 web.config 文件里配置。这取决于 Web 服务器的特性委托配置。

       applicationHost.config 位于系统目录的 inetsrv\config 子目录:

C:\Windows\System32\inetsrv\config

 

       默认情况下,IIS 特性委托会被配置,因此 web.config 会从中央配置 applicationHost.config 基础原生验证模块的设置,而 web.config 只包含 ASP.NET 特定的配置。

       不过,可以修改 IIS 特性委托配置,使得这些配置也保存在应用程序的 web.config 文件里。这样会使得应用程序的 xcopy 部署非常的方便,因为所有设置都可以直接保存在 web.config 里。

       下图显示选中验证模块的 IIS 7.x 特性配置(功能委派):[特性配置是基于整个 Web 服务器的]

image_thumb[7]

       可以看到,验证模块的特性委托由 IIS 7.x 原生提供,并被设置为只读。也就是说,这些设置由管理控制台在 applicationHost.config 文件中配置,并由 web.config 继承。它还意味着这些模块的配置设置不允许出现在应用程序的 web.config 配置里。因此,默认情况下,你不会在本地 web.config 文件里找到这些模块的任何配置设置。

       如果把它们或者其中之一的委派属性改为 读/写,这些配置就会出现在 web.config 文件里。如果把 Basic 和 Windows 的委派设置为 读/写,下面的节将被添加到 web.config 中(在控制台设置任何一个验证时被添加):

<system.web>
  <authentication mode="Windows" />
</system.web>
<system.webServer>
    <security>
        <authentication>
            <windowsAuthentication enabled="true" />
            <basicAuthentication enabled="true" />
        </authentication>
    </security>
</system.webServer>

       有一点要记住:如果在 web.config 中配置了原生模块的设置,中央特性委托配置设为了只读,在试图访问页面会得到一个 HTTP 500 内部服务器错误。试图配置相关的特性时,IIS 7.x 控制台也会返回一个错误:

image_thumb[9]

       这种情况下,你需要手工从 web.config 文件里把无效的配置项移除。

       默认情况下,功能委派对很多模块都是禁用的。这些模块在 IIS 7.x 的中央配置 applicationHost.config 里配置而不是通过应用程序的 web.config 配置。这些设置在功能委派界面有一个完整的列表。

 

禁止匿名用户访问

       可以通过配置 IIS 的虚拟目录或者在 web.config 文件中添加授权规则来强迫用户进行登录。第二种方式更好一些,能赋予你更多的灵活性。设置 web.config 文件中的 <authorization> 元素添加一个新的授权规则:

<system.web>
  <authorization>
    <deny users="?"/>
  </authorization>
</system.web>

       问号 ? 可匹配任何匿名用户,这意味着每一位用户必须经过某种 Windows 验证协议来进行验证。

 

       使用 IIS 控制台配置授权规则:

image_thumb[11]

       默认情况下,授权规则被添加到 applicationHost.config 文件中,它们不会反映到你的 web.config 中。

       这两种情况意味着什么?当使用控制台配置授权规则时,它们被配置到 <system.webServer> 节,它由 Web 服务器的原生授权模块使用,Web 服务器自身会拒绝请求。另一方面,当手动在 web.config 中配置时,ASP.NET 模块会拒绝请求(它在处理管道较后的时间点上)。

访问 Windows 用户信息

       Windows 验证非常好的一点就是不需要登录页面。当用户访问一个需要验证的页面时,浏览器将用户凭证传递给 IIS,然后 Web 程序就可以从网页的 User 属性直接获得这些信息:

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.IsAuthenticated)
    {
        // Display generic identity information
        lblInfo.Text = "<b>Name: </b>" + User.Identity.Name;
        lblInfo.Text += "<br /><b>Authenticated With: </b>" + User.Identity.AuthenticationType;
    }
}

       表单验证时也可以用这段代码获得用户的身份信息。但略有区别,见下图,用户名总是以 域名\用户名 或者 计算机名\用户名 的格式出现:

image_thumb[12]

 

1. WindowsPrincipal

       User 属性返回一个 IPrincipal 对象。当使用 Windows 验证时,这是 WindowsPrincipal 类的一个实例。WindowsPrincipal 实现了 IsInRole() 方法的 4 种重载,它们都被用来检查一个用户是否在某个指定的用户组中。

  • IsInRole(字符串):用于检查用户组名称,此方法是必须被实现的
  • IsInRole(整数):一个整数的 RID,角色ID,它执向某个用户组
  • IsInRole(WindowsBuiltInRole 枚举成员) :它提供 Windows 内置帐号类型,如 Guest、Administrator 等
  • IsInRole(SecurityIdentifier 类的实例)

       下面这段代码用来检查用户是否属于某个预先定义的 Windows 角色:

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.IsAuthenticated)
    {
        lblInfo.Text = "<b>Name: </b>" + User.Identity.Name;
 
        // WindowsPrincipal: 允许代码检查 Windows 用户的 Windows 组成员身份
        if (User is WindowsPrincipal)
        {
            WindowsPrincipal principal = (WindowsPrincipal)User;
            lblInfo.Text += "<br /><b>Power user? </b>";
            lblInfo.Text += principal.IsInRole(WindowsBuiltInRole.PowerUser);
        }
    }
}

image_thumb[13]

       必须把 User 对象强制转换为 WindowPrincipal 对象以此来访问 Windows 特色的功能。这一转换在激活了表单验证和角色 API 时不起作用。当启用角色API 时,即使为应用程序配置了 Windows 验证仍然无效,因为 ASP.NET 将创建一个 RolePrincipal 对象。

WindowsBuiltInRole 枚举值

  • Administrator管理员具有对计算机或域的完全的无限制的访问权限
  • User:受限的用户帐号,被禁止对系统进行改动
  • Guest:来宾受到比用户更多的限制
  • PowerUser:超级用户具有大部分管理员权限(但也受到某些限制)
  • AccountOperator:帐户操作员管理计算机或域中的用户帐户
  • SystemOperator:系统操作员管理特定的计算机
  • PrintOperator:打印操作员可以获得打印机的控制权
  • BackupOperator:备份操作员仅在出于备份或还原文件目的时才可以重写安全限制
  • Replicator:复制程序支持域中的文件复制

 

WindowsIdentity 的额外成员

       强制转换一个通常的 Identity 对象为 WindowsIdentity 对象,可以获得关于当前已验证用户的额外信息:

IsAnonymous 是否匿名用户
IsGuest 是否 Guest 账户
IsSystem 是否是一个被授予高级权限的系统帐号
Groups 获得包含 IdentityRefrence 类实例的集合,它返回用户所属的用户组的 SID 值
Token 返回用户身份的 Windows 账户令牌
Owner 获得令牌所有者的 SID
User 获得用户的 SID。通过 System.Security.AccessControl 命名空间提供的类来修改这个用户的 ACL 权限,可以用这个 SID
Impersonate() 告诉 ASP.NET 以相应的 Windows 帐号的身份执行后面的代码
GetAnonymous() 创建一个代表匿名用户的 WindowsIdentity 对象
GetCurrent() 创建代表与当前安全上下文捆绑在一起的用户身份的 WindowsIdentity 对象。如果在一个 ASP.NET 程序中使用这个方法,你会获得代码执行时所使用的用户身份,而不是被 IIS 所验证并通过 User 对象提供的用户帐号

       下面的代码显示了额外的与 Windows 相关的用户信息:

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.IsAuthenticated)
    {
        lblInfo.Text = "<b>Name: </b>" + User.Identity.Name;
 
        WindowsIdentity identity = (WindowsIdentity)User.Identity;
        lblInfo.Text += "<br /><b>Token: </b>" + identity.Token.ToString();
        lblInfo.Text += "<br /><b>Guest? </b>" + identity.IsGuest.ToString();
        lblInfo.Text += "<br /><b>System? </b>" + identity.IsSystem.ToString();
    }
}

image_thumb[15]

 

IdentityReference 和 角色信息

       IdentityReference 是一个通过 SID 来表示的有效 Windows 身份的引用。可以是 计算机\用户帐号 或 Windows 群组。当创建一个用户、或创建群组、或基于 Windows 安装机器时,系统会为其分配一个全球唯一的 SID 用来标识系统对象。

       例如,如果你通过文件属性的安全页签批准机器上的用户访问文件,则会在这个文件的访问控制列表中添加一个 IdentityReference,并且其上包含你所批准访问的用户的 SID 信息。当将一个用户加入到一个群组时,用户的引用也会以 SID 的形式添加到群组的用户列表中。

 

       System.Security.Principal 命名空间里包含了 3 个新的针对 SID 的类:IdentityReferenceSecurityIdentitierNTAccount这些类是通过一个 WindowsIdentity 实例来列举一个 Windows 用户群组的核心所在

       IdentityReference 是代表一个 SID 的任意类的抽象基类,SecurityIdentitierNTAccount 是它的子类。SecurityIdentitier 代表真实的、唯一的 SID 代码(看上去类似于 UUID),NTAccount 代表人类可读的 SID 字符串(比如用户名或者群组名)。

       IdentityReference 基类定义了一个 Translate(),允许将一个 IdentityReference 实例进行转换。例如,从 NTAccount 转换为 SecurityIdentifier。

理解了上面的知识,列举当前已登录的 Windows 用户帐号的群组就简单了,如下所示:

protected void Page_Load(object sender, EventArgs e)
{
    if (User is WindowsPrincipal)
    {
        // First of all, get general user information
        WindowsPrincipal principal=(WindowsPrincipal)User;
        WindowsIdentity identity = (WindowsIdentity)principal.Identity;
 
        // Get the roles for the user
        lblInfo.Text = "<h2>Roles:</h2>";
        foreach (IdentityReference SIDRef in identity.Groups)
        {
            lblInfo.Text += "<br />--";
 
            // Get the system code for the SID
            SecurityIdentifier sid = (SecurityIdentifier)SIDRef.Translate(typeof(SecurityIdentifier));
            lblInfo.Text += "<br /><b>SID(code): </b><br />" + sid.Value;
 
            // Get the human-readable SID
            NTAccount account = (NTAccount)SIDRef.Translate(typeof(NTAccount));
            lblInfo.Text += "<br /><b>SID(human-readable): </b><br />" + account.Value;
        }
    }
 
}

image_thumb[17]

       .NET Framework 有两种表示 IdentityReference 对象的类型:SecurityIdentifier 表示 SID,它是系统内部编码;NTAccount 表示人类可读的 SID 版本。

posted on 2013-04-15 16:37  SkySoot  阅读(559)  评论(0编辑  收藏  举报

导航