【问题标题】:Mixing Windows and Forms authentication in .NET 4.5: how to keep Request.IsAuthenticated = false until after forms authentication ticket is created?在 .NET 4.5 中混合 Windows 和 Forms 身份验证:如何保持 Request.IsAuthenticated = false 直到创建表单身份验证票证?
【发布时间】:2014-01-18 17:30:59
【问题描述】:

更新:

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

原始问题:

我有一个同时使用 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 auth 进行身份验证之后,但在通过 Forms auth 进行身份验证之前(创建表单身份验证票证/cookie),Global.Application_AuthenticateRequest() 看到 Request.IsAuthenticated 是 @ 987654326@。一旦Request.IsAuthenticated 变为trueSystem.Web.HttpContext.Current.User 的类型为System.Security.Principal.GenericPrincipal(而User.IdentitySystem.Web.Security.FormsIdentity

在 IIS7 服务器上安装 .NET 4.5 后,此行为发生了变化。未对 Web.config 文件进行任何更改,也未对 IIS 进行手动更改。我所做的唯一更改是安装 .NET 4.5。卸载 4.5 并重新安装 4.0 后,该行为恢复为“正常”。

我注意到的不同行为是,在通过 Windows 成功进行身份验证之后,但在通过表单进行身份验证之前(尚未创建表单身份验证票证),Application_AuthenticateRequest 现在显示Request.IsAuthenticatedtrue。 此外,System.Web.HttpContext.Current.User.Identity 现在是 System.Security.Principal.WindowsIdentity(而不是 FormsIdentity)。

  1. 有人能解释一下为什么会有所不同吗?
  2. 是否有一个配置选项(如 web.config 更改或 IIS 设置)可以用来强制它以 4.0 方式工作? (这样就设置Request.IsAuthenticated = true 而言,Windows 身份验证不会胜过表单身份验证?)

我已经搜索了几个小时的 Msft 文档.. 他们所有关于混合 Windows 和 Forms 身份验证的信息似乎都已经过时了(2004 年左右),而关于 .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
        }
    }

【问题讨论】:

  • 我认为这个链接会对你有所帮助:stackoverflow.com/questions/12021863/…
  • 您确定框架版本是唯一完成的更改吗?您的应用程序是在 IIS 7 的集成模式还是经典模式下运行。在您站点的应用程序池中查找托管管道。尝试更改模式。
  • 它使用集成管道(安装4.5之前和之后)。唯一的变化是安装了 4.5。通过卸载 4.5 并重新安装 4.0 确认这一点:工作正常。然后我再次安装了 Framework v4.5,它又回到了这个不同的流程。

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


【解决方案1】:

Re: 谁能解释一下为什么不一样?

我注意到 System.Web.Hosting.IIS7WorkerRequest.SynchronizeVariables() 在 4.5 中进行了更改。区别如下图(源码来自reflector):

在 4.0 中,SynchronizeVariables() 仅在启用 Windows 身份验证的情况下同步 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 不会进行表单身份验证。

【讨论】:

  • 感谢您的解释。这似乎证实了为什么我还没有通过简单的设置更改找到解决此问题的方法。我已经准备好在补丁中修复代码,但不幸的是,微软没有更好地记录这一点(据我所知),因为这是这个特定应用程序的重大更改。哦,好吧..
  • @nothingisnecessary 请问您是如何解决这个问题的?即如何在 4.5 中对管理员用户启用表单身份验证时对所有用户启用 Windows 身份验证?
  • 我从一阶段认证到两阶段。与本文中的解决方案没有什么不同:mvolo.com/… 不幸的是,我不允许共享代码,因为我可能会失业,但基本上:一个表单处理 windows auth(包括匿名),然后重定向到表单 auth,这要么挑战用户(如果尚未通过身份验证),或根据映射的 Windows 登录通过我们的 SSO 进程传递表单凭据。
【解决方案2】:

更新:

我通过实现两阶段身份验证(首先是 Windows 身份验证(如果启用),然后是表单身份验证)解决了这个问题,并且完全避免使用 Request.IsAuthenticated

我在我项目的一个公共库中创建了一个静态属性:Security.User.IsAuthenticated,现在在我之前使用Request.IsAuthenticated 的地方使用它。现在,我可以完全控制我的应用程序中“已验证”的含义。 (首先应该这样做;随着时间的流逝,我经常发现自己像这样包装现有的 .NET 功能,以便更好地控制!)

抱歉,无法透露确切的细节,但基本上它涉及检查当前请求的上下文 (System.Web.HttpContext.Current) 中的一些内容,这些内容是在成功登录后创建表单身份验证票证时设置的(无论是通过 SSO 还是其他方式) .希望这可以帮助某人...

这是我创建的属性。 (真正的工作是由 ProprietaryAuthenticationFunction() 完成的,这应该是您的应用程序需要做的任何事情来验证数据库、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,您可以省略这些部分。如果您发现任何问题/安全漏洞/性能注意事项,请告诉我或其他,谢谢!)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-21
    • 2011-01-16
    • 1970-01-01
    • 2023-03-22
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 2011-03-12
    相关资源
    最近更新 更多