ASP.NET中的Forms和Windows混合验证

来源:互联网 发布:美国人的穿衣风格数据 编辑:程序博客网 时间:2024/05/16 08:16

本文翻译自:Mixing Forms and Windows Security in ASP.NET

 

摘要:ASP.NET开发人员曾经问到过如何使用Forms和Windows混合验证。Paul Wilson提供了一个解决方案来获得Windows用户名,或者,将用户转向登录页面。

 

简介

 

我曾经遇到很多ASP.NET开发人员问到如何使用Forms和Windows混合验证。通常的回答是:“ASP.NET不支持混合验证”。不谈技术细节,让我们先从业务的角度来看一下。我们要做的是自动取得域用户名,并且将其他用户转向登录页面。这样可行吗?当然。

 

Forms验证

 

首先,需要确定要使用哪种ASP.NET验证。想要使用Forms和Windows混合验证并不容易,一个ASP.NET应用程序只能有一种验证方式,所以你只能选择其中一种。Windows验证只能提供用户名,就是ASP.NET的进程用户,或者客户端的用户名(如果在IIS里禁止了匿名登录的话)。明白了这个以后,很明显,只有Forms验证才是可以定制的。

我们来对程序中的web.config设置Forms验证。需要指出的是,你要确定你的ASP.NET应用程序是一个IIS应用,对任何验证方式这都是必须的。同时,需要在web.config里设置拒绝匿名用户。web.config中的authentication节点拥有一些属性,loginUrl定义了未验证用户将重定向到的登录页的URL。

接下来,你需要确定哪个页面将作为ASP.NET应用的loginUrl。在所有我曾经看到过的Forms验证中,是Login.aspx页。但是,你想要首先通过Windows验证用户而不是使用登录页面,所以,你的loginUrl应该是一个使用Windows集成验证的页面。于是,我们需要将Forms验证的loginUrl设置到WinLogin.aspx.

 

IIS Windows验证

 

接着,我们需要设置WinLogin.aspx页面的Windows集成验证。这里一共有几个步骤,包括,拒绝匿名访问,获取客户端Windows凭证,获取客户端Windows用户名,然后插入Forms验证中。我们将在稍后处理Windows集成验证失败的情况。WinLogin.aspx只是用来测试集成Windows验证,没有html。

我们来看如何拒绝匿名访问和取得客户端Windows证书。这个问题的描述将会使你明白IIS已经拥有了这些功能,你可以直接使用它们来解决问题。打开IIS,右键点击WinLogin.aspx文件,打开属性设置,在“文件安全性”标签中,取消选中“匿名访问”,然后选中“集成Windows身份验证”来设置这个文件的访问控制。

但是,这样并不能自动取得用户名,我们还需要做一些设置。通过跟踪页面,或者反编译WindowsAuthenticationModule中的OnEnter方法,你可以找到解决方法。用户名保存在名为LOGON_USER服务器端变量中。你只需要通过Request.ServerVariables["LOGON_USER"]取得用户名,然后调用FormsAuthentication.RedirectFromLoginPage将其插入Forms验证即可,这样就设置了验证cookie同时转向源页面。

Windows集成验证

 

IIS 401错误

 

现在,集成Windows验证的工作已经完成了。但是,我们还需要处理Windows验证失败的状况,应该将他们转向用户登录画面来进行验证。需要注意,Windows集成验证依赖于浏览器,使用非IE浏览器的用户可以在显示登录框时选择取消,这会导致Windows集成验证失败。我们还要明白在Windows集成验证失败时将会发生什么。

Windows集成验证失败时,用户会收到一个401错误。ASP.NET在web.config中内置了一个特性来获取和转向大部分错误,但是,401和403错误例外,必须通过其他方法来处理。我不知道用什么方法可以处理401错误而不需要同IIS发生关系。

打开IIS,右键点击WinLogin.aspx文件,打开属性设置,在“自定义错误”标签中,为所有的401类型错误设置一个自定义转向。在这里,转向文件必须是一个静态页面,而不能是ASP.NET页面。我的解决方法是,将转向路径设置到Redirect401.htm文件的物理地址,这个文件中包含一段javascript或者meta标签,来自动转向到ASP.NET登录页面WebLogin.aspx。注意,因为IIS错误转向需要一个静态页面,会失去原始的ReturnUrl,所以你需要在将来处理这个问题。

Redirect 401 errors to a custom error page

 

页面用户登录

 

接下来,需要创建Forms验证的登录页面,命名为WebLogin.aspx。这个页面只要需要包含让用户输入用户名和密码的文本框,以及登录按钮,也许你还需要其他的一些登录相关的属性。还要在登录按钮的时间中加入验证代码,示例代码中只是简单的测试用户名和密码是否相同。你也许还需要添加对自定义角色或者Windows角色的支持。

现在,已经取得验证过的用户,以及相应的用户名。你可以通过调用FormsAuthentication.RedirectFromLoginPage来讲这些信息加入到Forms authentication中,但是由于我们已经丢失了原始的ReturnUrl,所以它看起来并不是很好。我们需要单独设置验证cookie,使用FormsAuthentication.SetAuthCookie然后手动转向到原始的ReturnUrl,我们马上会解决这个。看起来应该可以了,但是你会发现重新进入了WinLogin.aspx。

为什么没有进入WebLogin.aspx页面?因为还没有设置合适的权限。你已经设置了Forms验证而且拒绝匿名访问,这可以自动的将匿名用户转向到loginUrl,也就是WinLogin.aspx。所以,你还需要设置WebLogin.aspx的权限来允许匿名用户访问,通过web.config中的location节点,可以很容易的进行设置。现在,你已经成功的设置了Forms和Windows混合验证。

 

重定向原始的Url

 

现在,唯一的问题就是追踪原始的Url,来进行重定向。Forms验证模块自动为WinLogin.aspx添加了一个ReturnUrl的querystring,但是集成Windows验证拒绝非Windows用户的访问。然后,IIS将你转向到一个静态的html文件,querystring会丢失。你需要使用一些更持久的东西来追哦那个原始的Url,比如cookies或者session。我们需要知道如何获取原始的Url和保存它。

Forms验证使用HttpModule来获取和处理所有的请求,在原始的请求页面加载前将未验证的用户转向。这意味着你需要在更早一些的时间来处理请求,比如在global.asax里,你可以处理其中的AuthenticateRequest事件来获取原始的Url。所以,检查请求是否经过验证,然后将请求的路径放进ReturnUrl cookie中,这样你就可以在WebLogin.aspx页面中使用它来转向了。

看起来没问题了,但是你会重新进入WebLogin.aspx,而不是原始的URL。debug一下很容易就会发现问题所在,在请求WebLogin.aspx时你重写了ReturnUrl cookie,所以对这种情况不要修改cookie。这样,会有一个新的情况,用户可以直接进入WebLogin.aspx,这时没有ReturnUrl cookie,你需要检查和处理这个问题。现在,你已经成功的设置了Forms和Windows混合验证,而且有了原始的转向。

Mixing Forms and Windows security in ASP.NET

 

总结

 

让我们再看看我们都做了些什么,为什么看起来那么困难。我们的问题是使用Forms和Windows混合验证。开发人员倾向于跳过技术细节,告诉你不能使用混合验证。但是用户不关心有多少验证方式,为什么我们要在意?我们需要仔细看一下用户需要的是什么,在这个问题里就是,获取他们的Windows用户名,或者将他们转向到登陆页面。

 

关于作者

 

Paul Wilson is a software architect in Atlanta who recently joined the development team at PRG-Schultz. His WilsonWebForm control allows multiple forms and non-post-back forms in ASP.NET. He is a Microsoft Most Valuable Professional in ASP.NET, a moderator of Microsoft's ASP.NET Forums, a Microsoft Certified Solution Developer, a Microsoft Certified Application Developer, a Microsoft Certified Data Base Administrator, and a Microsoft Certified Systems Engineer. Visit his website, http://www.WilsonDotNet.com, or e-mail him at Paul@WilsonDotNet.com.