16.3 基于Windows的身份验证
知识点讲解:光盘:视频\PPT讲解(知识点)\第16章\基于Windows的身份验证.mp4
在本书前面的内容中,讲解设置SQL Server 2005的章节时,曾经学习过Windows的身份验证的知识,并且还知道有另外一个选项是混合模式。这两种模式是有所差别的,Windows身份验证模式只进行Windows身份验证,用户不能指定SQL Server登录ID,这是SQL Server的默认身份验证模式。如果用户在登录时提供了SQL Server登录ID,则系统将使用SQL Server身份验证对其进行验证。如果没有提供SQL Server登录ID或请求Windows身份验证,则使用Windows身份验证对其进行身份验证。
基于Windows的身份验证的基本处理过程如下。
(1)获取网络客户端的请求,并进入IIS。
(2)IIS使用基本、简要或Windows集成的安全(NTLM或Kerberos)对客户端进行身份验证。
(3)如果客户端通过了身份验证,则IIS将已通过身份验证的请求传递给ASP.NET。
(4)ASP.NET应用程序使用从IIS传递来的访问标识模拟发出请求的客户端,并依赖于NTFS文件权限来授予对资源的访问权。ASP.NET应用程序只需验证是否在ASP.NET配置文件中将模拟设置为True,不需要ASP.NET安全码。如果未启用模拟,则应用程序将使用ASP.NET进程标识运行。对于Microsoft Windows 2000 Server和Windows XP Professional,默认标识是在安装ASP.NET时自动创建的、名为ASPNET的本地账户。对于Microsoft Windows Server 2003,默认标识是用于IIS应用程序的应用程序池标识(默认情况下为Network Service账户)。
(5)如果允许访问,则ASP.NET应用程序通过IIS返回请求的资源。
上述过程的运行流程如图16-10所示。
图16-10 Windows的身份验证流程
16.3.1 配置IIS安全
使用基于Windows的身份验证之前,首先需要配置IIS。具体配置界面如图16-11所示。
图16-11 IIS中配置身份验证方法
由图16-11所示的界面可以看出,IIS 5.1支持以下3种身份验证方式(需要禁止匿名访问)。
- 基本身份验证。与所有的浏览器和防火墙兼容,但是用户名和密码在网络上是以明文发送的。
- 集成Windows身份验证。不与所有的防火墙和代理服务器兼容,与IE浏览器兼容。用户名和密码不以明文发送。
- 摘要式身份验证。与所有的防火墙和代理服务器兼容,与IE浏览器兼容。用户名和密码不以明文进行发送,但是会保存在域服务器的明文文件中。
通常有两种方式禁止匿名用户访问文件或目录,具体如下。
- 在IIS中配置禁止对某个目录的匿名访问。
- 配置NTFS权限,禁止匿名用户或者Guests用户组访问文件夹。这样,即使启用了匿名访问,匿名用户最终还是没有权限访问文件或者目录。
16.3.2 配置Windows安全
在Windows系统中包含了如下3个默认的用户组。
- Administrators组:具有最大,最多的权限。
- Everyone组:自动包含当前域中经过身份验证的每一个用户。
- Guests组:IIS所关联的匿名账户默认隶属于Guests组,如图16-12所示。
图16-12 匿名用户账户
NTFS的权限控制采用继承机制,默认情况下d:\Text目录会继承d:的配置。因此,如果尝试修改从父项继承的权限(如修改d:\Text文件夹自动从d:继承的权限),会得到如图16-13所示的系统提示。
图16-13 操作继承权限的提示
此时如果单击“高级”选项,然后取消勾选的“从父项继承权限”,如图16-14所示。
图16-14 选择处理已经继承权限的方式
在此单击【复制】按钮,应用于父项的权限会全部复制到这个文件夹上,这样,这个文件夹就拥有了独立的权限。然后就可以对这些权限进行修改了。
16.3.3 配置Windows身份验证和授权
默认情况下,所有的ASP.NET应用程序都使用基于Windows的身份验证方式,如果修改machine.config中的验证方式,则可以通过单独配置某个ASP.NET应用程序根目录下的Web.config文件来应用Windows身份验证。具体配置代码如下。
<configuration>
<system.web>
<authentication mode="Windows"/>
</system.web>
</configuration>
在启用Windows身份验证之后,可以通过配置Web.config文件来向特定的用户和组授予特定目录或文件的权限,这就是配置授权。
通过配置如下文件可以拒绝匿名用户的访问。
<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
其中,users代表一个或者多个用户(多个用户之间使用逗号分隔)。问号“?”表示所有未经过身份验证的用户(匿名用户);星号“*”表示所有用户。
授权配置在<authorization>节点下,身份验证方式配置在<authentication>节点下。这两个节点名称的英语单词比较容易混淆,读者需注意分辨。
<deny>节点表示拒绝,还可以使用<allow>节点来表示允许,例如下面的配置代码。
<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<allow users="xxx\nnnn"/>
<deny users="*"/>
</authorization>
</system.web>
</configuration>
这样就表示拒绝所有用户,只允许Magicgrids域下的yzhu用户访问文件或者目录。读者可能会奇怪,拒绝所有用户和允许一个用户之间有矛盾。其实,授权部分使用的是第一匹配算法,允许的配置在拒绝前出现,ASP.NET看到允许后就直接放行用户而不会“追究”之后的拒绝。
读者在此还需要注意以下两点。
- 如果配置NTFS文件夹允许Everyone用户组(代表所有已经通过身份验证的用户)访问,那么就等于是进行了<allow users="*"/>的配置。
- 所有对于用户或者用户组的授权都必须是域名\用户名的格式。如果是本机用户,就在域名处写上计算机名或者一个点号“.”。
读者按照笔者在本书中介绍的配置方法可能会打不开页面,这是因为你登录计算机的身份并不是xxx\nnnn用户,因此出现如图16-15所示的对话框。此时读者应该根据自己机器下的域名和用户名进行配置,以避免出现登录错误。
图16-15 未授权的用户尝试访问文件夹
16.3.4 自定义角色
有时可能不能直接使用Windows的用户组来授权用户,此时,可以使用编程的方式创建一个全局应用程序类Global.asax在里面定义一个自定义角色,代码如下。
<%@ Application Language="C#|" %>
<script runat="server">
void WindowsAuthentication_OnAuthenticate(Object Source,
WindowsAuthenticationEventArgs e)
{
System.Collections.Generic.Dictionary<string, string[]> myRoles = new System.
Collections.Generic.Dictionary<string, string[]>();
myRoles.Add(@"magicgrids\yzhu", new string[] { "myGroup" });
if(myRoles.ContainsKey(e.Identity.Name.ToLower()))
e.User = new System.Security.Principal.GenericPrincipal(e.Identity,
myRoles[e.Identity.Name.ToLower()]);
}
</script>
在上述代码中,定义了一个字典,用于存储用户和与它关联的用户组。在这里,我们把xxx\mmm这个用户关联到了自定义的用户组“myGroup”中。然后对Web.config文件进行如下修改。
<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<allow roles="myGroup"/>
<deny users="*"/>
</authorization>
</system.web>
</configuration>
经过重新编译程序后页面还能正常打开,说明自定义用户组成功。在具体应用中,可以把用户和用户组数据保存在数据库中,然后在全局应用程序类中加载自定义用户组,在Web.config文件中授权用户组。
16.3.5 获取用户信息
如果觉得通过Web.config文件进行授权不是很方便,还可以直接读取当前访问页面的(域)用户信息来使用编程方式手动授权。读取用户标识名和判断用户是否在某个用户组中的代码如下。
Response.Write(User.Identity.Name + "<br/>");
Response.Write(User.IsInRole("myGroup") + "<br/>");
可以通过判断用户名来获取用户身份,然后根据用户身份给予不同的反馈。也可以通过判断用户是否在一个用户组内进行相应的反馈。