我通过一些相当简单的更改解决了这个问题,请参阅下面的自我回答.
原始问题:
我有一个ASP.NET Web应用程序,它使用Windows身份验证和表单身份验证.表单身份验证定义为Web.config中的身份验证模式(参见下面的摘录).在IIS 7中,在Web应用程序(AKA虚拟目录)级别,禁用匿名身份验证,并启用Windows身份验证.
在通过Windows身份验证成功进行身份验证后,但在通过Forms身份验证(创建表单身份验证票证/ cookie)进行身份验证之前,在.NET 1.1到.NET 4.0和IIS6 / 7 / 7.5中,Global.Application_AuthenticateRequest()看到Request.IsAuthenticated为false.一旦Request.IsAuthenticated变为true,System.Web.HttpContext.Current.User的类型为System.Security.Principal.GenericPrincipal(并且User.Identity为System.Web.Security.FormsIdentity)
在IIS7服务器上安装.NET 4.5后,此行为已更改.未对Web.config文件进行任何更改,并且未对IIS手动进行任何更改.我做的唯一改变是安装.NET 4.5.卸载4.5并重新安装4.0后,该行为恢复为“正常”.
我注意到的不同行为是,在通过Windows成功进行身份验证之后,但在通过表单进行身份验证之前(尚未创建表单身份验证票证),Application_AuthenticateRequest现在显示Request.IsAuthenticated为true.
此外,System.Web.HttpContext.Current.User.Identity现在是System.Security.Principal.WindowsIdentity(而不是FormsIdentity).
>有人可以解释为什么这是不同的?
>是否有可用于强制它以4.0方式工作的配置选项(如web.config更改或IIS设置)? (因此,对于设置Request.IsAuthenticated = true,windows auth不会胜过表单身份验证?)
我一直在搜索Msft文档几个小时..他们关于混合Windows和Forms auth的所有信息似乎都已过时(2004-ish),而且.NET 4.5的更改细节在这一特定领域相当稀少.
摘自web.config :(是的,default.aspx是故意的,在这种情况下我不使用login.aspx,但它已经工作了5年并且在所有以前的.net版本中都运行良好).
<authentication mode="Forms"> <forms name=".ASPXAUTH" protection="All" timeout="200" loginUrl="default.aspx" defaultUrl="~/default.aspx" /> </authentication>
摘自Global.asax.cs:
protected void Application_AuthenticateRequest(Object sender,EventArgs e) { if (Request.IsAuthenticated) { // stuff for authenticated users // prior to upgrading to .NET 4.5,this block was not hit until // after the forms authentication ticket was created successfully // (after validating user and password against app-specific database) } else { // stuff for unauthenticated users // prior to upgrading to .NET 4.5,this block was hit // AFTER windows auth passed but BEFORE forms auth passed } }
解决方法
我注意到System.Web.Hosting.IIS7WorkerRequest.SynchronizeVariables()的更改是在4.5中进行的.差异如下所示(源代码来自反射器):
在4.0中,如果启用了Windows身份验证,则SynchronizeVariables()仅同步IPrincipal / IHttpUser.
internal void SynchronizeVariables(HttpContext context) { ... if (context.IsChangeInUserPrincipal && WindowsAuthenticationModule.IsEnabled) // the second condition checks if authentication.Mode == AuthenticationMode.Windows { context.SetPrincipalNoDemand(this.GetUserPrincipal(),false); } ... }
在4.5中,如果启用了任何身份验证,SynchronizeVariables()会同步IPrincipal / IHttpUser(AuthenticationConfig.Mode!= AuthenticationMode.None)
[PermissionSet(SecurityAction.Assert,Unrestricted=true)] internal void SynchronizeVariables(HttpContext context) { ... if (context.IsChangeInUserPrincipal && IsAuthenticationEnabled) { context.SetPrincipalNoDemand(this.GetUserPrincipal(),false); } ... } private static bool IsAuthenticationEnabled { get { if (!s_AuthenticationChecked) { bool flag = AuthenticationConfig.Mode != AuthenticationMode.None; s_AuthenticationEnabled = flag; s_AuthenticationChecked = true; } return s_AuthenticationEnabled; } }
我怀疑上述更改是身份验证中行为更改的根本原因.
在更改之前:ASP.NET不与IIS同步以获取用户的Windows身份(虽然IIS确实使Windows认证).由于未进行身份验证,ASP.NET仍可以执行表单身份验证.
更改后:ASP.NET与IIS同步以获取用户的Windows标识.因为设置了context.Current.User,所以ASP.NET不会进行表单身份验证.