在.NET 4.5中混合Windows和Forms身份验证:如何在创建表单身份验证票证之前保留Request.IsAuthenticated = false?

时间:2013-12-31 20:58:19

标签: asp.net authentication iis webforms .net-4.5

更新:

我通过一些相当简单的更改解决了这个问题,请参阅下面的自我回答。

原始问题:

我有一个使用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.IsAuthenticatedtrue的类型为System.Web.HttpContext.Current.UserSystem.Security.Principal.GenericPrincipalUser.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)。

  1. 有人可以解释为什么会有所不同吗?
  2. 是否有可用于强制它以4.0方式工作的配置选项(如web.config更改或IIS设置)? (因此,对于设置System.Security.Principal.WindowsIdentity而言,Windows身份验证不会胜过表单身份验证?)
  3. 我一直在搜索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

2 个答案:

答案 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,则可以省略这些部分。如果您发现任何问题,请告诉我们/安全漏洞/性能考虑因素或其他,谢谢!)