更新:
我通过一些相当简单的更改解决了这个问题,请参阅下面的自我回答。
原始问题:
我有一个使用Windows身份验证和Forms身份验证的ASP.NET Web应用程序。 Forms
身份验证定义为Web.config中的authentication mode
(参见下面的摘录)。在IIS 7中,在Web应用程序(AKA虚拟目录)级别,禁用匿名身份验证,并启用Windows身份验证。
在.NET 1.1到.NET 4.0和IIS6 / 7 / 7.5中通过Windows身份验证成功进行身份验证后,但在通过Forms身份验证进行身份验证(创建表单身份验证票证/ cookie)之前,Global.Application_AuthenticateRequest()
看到{{1}是Request.IsAuthenticated
。一旦false
变为Request.IsAuthenticated
,true
的类型为System.Web.HttpContext.Current.User
(System.Security.Principal.GenericPrincipal
为User.Identity
)
在IIS7服务器上安装.NET 4.5后,此行为已更改。未对Web.config文件进行任何更改,并且未对IIS手动进行任何更改。我做的唯一改变是安装.NET 4.5。卸载4.5并重新安装4.0后,该行为恢复为“正常”。
我注意到的不同行为是,在通过Windows成功进行身份验证之后,但在通过表单进行身份验证之前(尚未创建表单身份验证票证),System.Web.Security.FormsIdentity
现在显示Application_AuthenticateRequest
为{{1 }}。
此外,Request.IsAuthenticated
现在是true
(而不是System.Web.HttpContext.Current.User.Identity
)。
System.Security.Principal.WindowsIdentity
而言,Windows身份验证不会胜过表单身份验证?)我一直在搜索Msft文档几个小时..他们关于混合Windows和Forms auth的所有信息似乎已经过时(2004-ish),并且关于.NET 4.5的更改的细节在这个特定的相当稀疏区域。
摘自web.config :(是的,default.aspx是故意的,在这种情况下我不使用login.aspx,但它在5年以上以及所有以前的.net版本中都运行良好)。< / p>
FormsIdentity
摘自Global.asax.cs:
Request.IsAuthenticated = true
答案 0 :(得分:4)
回复:有人可以解释为什么会有所不同吗?
我注意到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不会进行表单身份验证。
答案 1 :(得分:2)
更新:
我通过实现两阶段身份验证(首先是Windows身份验证(如果已启用),然后执行身份验证)以及完全避免使用Request.IsAuthenticated
来解决此问题。
我在我项目的一个公共库中创建了一个静态属性:Security.User.IsAuthenticated
,现在使用我之前使用Request.IsAuthenticated
的地方。现在我可以完全控制&#34;经过身份验证&#34;在我的申请中意味着。 (首先应该这样做;随着岁月的流逝,我经常发现自己包装现有的.NET功能,以便给予我更好的控制!)
很抱歉,无法透露确切的详细信息,但基本上它涉及检查当前请求的上下文(System.Web.HttpContext.Current
)中的一些内容,这些内容在成功创建表单身份验证票证时设置登录(无论是通过SSO还是其他方式)。希望这有助于某人...
这是我创建的属性。 (真正的工作是由OwnerAuthenticationFunction()完成的,应该是您的应用程序需要做的任何事情来验证数据库,LDAP或其他任何。抱歉,不能与您共享该代码,因为它会违反条款我的合同,但大多数企业应用程序应该已经拥有自己的专有身份验证功能。)
/// <summary>
/// This only returns true when current request is authenticated via forms
/// authentication, meaning the user is logged into the proprietary web app
/// (whether by manual login with user/pass or by single sign-on) AND has
/// passed whatever authentication method is used by IIS.
/// </summary>
public static bool IsAuthenticated
{
get
{
bool isAuth =
System.Web.HttpContext.Current != null &&
System.Web.HttpContext.Current.Request != null &&
System.Web.HttpContext.Current.Application != null &&
System.Web.HttpContext.Current.Session != null &&
System.Web.HttpContext.Current.Request.IsAuthenticated &&
ProprietaryAuthenticationFunction(System.Web.HttpContext.Current.Application, System.Web.HttpContext.Current.Session);
return isAuth;
}
}
(请注意,此特定网络应用会大量使用Session
,但如果您不关心Session
,则可以省略这些部分。如果您发现任何问题,请告诉我们/安全漏洞/性能考虑因素或其他,谢谢!)