表单身份验证 - 为每个请求执行的 loginUrl 页面(仅 Chrome)

Forms Authentication - loginUrl page executed for each request (Chrome only)

我想我已经尽可能减少了。它仅在使用表单身份验证时发生,并且似乎仅在 IE 中有效。到目前为止,我发现 Chrome 和 Firefox 都会导致这个问题。我有一个非常简单的 ASP 页面,它在每次页面加载时递增一个计数器(存储在会话变量中)。该页面名为 test.asp 并出现在我的网站根目录中。内容如下:

<%
    ' Write the last value (obviously blank the first time)...
    Response.Write "Last Num: " & Session("Num") &  "<br>"

    ' Increment the counter...
    Session("Num") = Session("Num") + 1

    ' Show the number we just saved...
    Response.Write "This Num: " & Session("Num") & "<br>"

    ' Throw the session ID out there, too, to make sure it's consistent...
    Response.Write "Session ID: " & Session.SessionID
%>

<form method="post" action="test.asp">
    <input type="submit" value="Submit">
</form>

我已经尽可能地精简了我的 web.config,同时仍然重现问题。以下是其内容:

<configuration>
    <system.webServer>  
        <modules runAllManagedModulesForAllRequests="true" />
    </system.webServer>
    <system.web>
        <authorization>         
            <deny users="?" />          
            <allow users="*" />         
        </authorization>
        <authentication mode="Forms">
            <forms loginUrl="test.asp" />
        </authentication>
    </system.web>
</configuration>

这里是非常基本的东西。我已将 test.asp 设置为 "login" 页面并启用 runAllManagedModulesForAllRequests。事情按预期工作。如您所料,所有请求都重定向到 test.asptest.asp 加载正常,除了接下来发生的事情...

初始加载和提交后页面在 IE (v11)、Chrome (v44) 和 Firefox (v39) 中的显示方式如下:

Internet Explorer 11:

Google Chrome 44:

Mozilla Firefox 39:

当我点击 [Submit] 时,我显然希望 Last Num 值等于之前的 This Num。但这只发生在 IE 中。在Chrome中,它似乎在做一个额外的增量。而在 Firefox 中,它似乎在做 two!更令人困惑的是,在初次提交之后,Firefox 每次都会适当地递增 1。 Chrome,但是,每次提交都会继续加倍。

这些是默认的浏览器安装。没有添加扩展或特殊配置。所有三个浏览器都启用了 Cookie(默认)。我可以使用每个浏览器的开发人员工具看到 ASPSESSIONID cookie。而且,正如您在屏幕截图中看到的,Session ID 是在页面加载时创建的,并在整个会话期间保持一致。

如果我继续提交,结果是一样的。 IE 继续正常工作。其他浏览器继续增加一倍或三倍。

有人以前见过这个问题吗?或者看看我在这里可能哪里出错了?我也尝试在 web.config<forms> 部分中指定 cookieless="UseCookies"

编辑 1 - 在别处测试:

到目前为止,我的所有测试都是在我的本地 PC 上进行的:Windows 7 64 位和 IIS 7.5。今天,我连接到我最终的测试服务器——一个 Windows Server 2008 R2 盒子,也装有 IIS 7.5——我的测试页面得到了相同的结果。

编辑 2 - loginUrl 相关?

使用具有相同内容的新页面 test2.asp(并通过我的 web.config 中的 <location> 元素明确匿名访问)工作正常。所以好像和loginUrl有关?也许对于每个页面请求,它都在幕后调用 loginUrl 页面?但同样,与 Chrome/Firefox...

有某种联系

编辑 3 - 更多证明:

我决定在每次执行页面时记录This Num的值。这是我看到的:

Internet Explorer:

8/4/2015 11:52:07 AM, Num=[1]    Initial page load. One execution.
-----------------------------
8/4/2015 11:52:11 AM, Num=[2]    All future submissions run once.
8/4/2015 11:52:16 AM, Num=[3]
8/4/2015 11:52:20 AM, Num=[4]

Chrome:

8/4/2015 11:34:58 AM, Num=[1]    I get 2 executions on initial page load.     
8/4/2015 11:35:00 AM, Num=[2]    First execution (Num=1) appears in browser.
-----------------------------
8/4/2015 11:35:29 AM, Num=[3]    Every submit causes page to run twice.
8/4/2015 11:35:29 AM, Num=[4]
-----------------------------
8/4/2015 11:35:49 AM, Num=[5]
8/4/2015 11:35:49 AM, Num=[6]

Firefox:

8/4/2015 11:36:25 AM, Num=[1]    I get 3 executions on initial page load.
8/4/2015 11:36:25 AM, Num=[2]    The first execution (Num=1) is the page
8/4/2015 11:36:25 AM, Num=[3]    I see in the browser.
-----------------------------
8/4/2015 11:36:34 AM, Num=[4]    All future submissions run once.
8/4/2015 11:36:43 AM, Num=[5]
8/4/2015 11:36:48 AM, Num=[6]
8/4/2015 11:36:53 AM, Num=[7]

编辑 4 - 每次请求时调用 loginUrl 页面:

似乎任何类型的页面请求都会导致 test.asp 在幕后执行,这会增加会话变量。这一定是因为它是由 loginUrl 为 Forms Auth 标识的页面。结合我在编辑 2 和编辑 3 下所做的测试,我授予匿名访问新测试页面 (test2.asp) 的权限,该页面没有做任何特别的事情——只是加载一个静态页面。这是:

<html><body>I'm test2.asp</body></html>

然后我监视了 test.asp 在运行时附加到的日志文件。每次我请求 test2,我都会在日志中得到一个新条目。因此,每次我发出页面请求时,test.asp 都会在后台运行(并增加会话变量)。下面是日志如何处理对我的 test2 页面的三个请求:

8/4/2015 12:20:57 PM, Num=[3]
8/4/2015 12:21:07 PM, Num=[4]
8/4/2015 12:21:14 PM, Num=[5]

test2.asp 不会对会话变量(也不会记录)做任何事情,但有证据。因此,出于某种原因,在 Chrome 上,它会针对每个请求运行 loginUrl 页面。我想我可以考虑证明这一点。现在我只需要一个解决方案!

尝试<forms loginUrl="test.asp" timeout="2880" cookieless="UseCookies" />

在 Fiddler 的帮助下,我解决了这个问题。

似乎 Chrome 和 Firefox 都对您的 favicon.ico 提出了额外的请求,无论您是否指定在 HTLM 页面中使用一个请求。另一方面,Internet Explorer 不会打扰。

由于以下几个原因,这对我来说是个问题:

  1. 我没有。我刚刚开始我的网站并创建 favicon.ico 是第 274 步。
  2. 我正在使用 runAllManagedModulesForAllRequests,因此对图标的请求与所有内容一样,通过表单身份验证运行。
  3. 如果您不 <link> 一个并指定它的位置,Chrome 和 Firefox 会尝试从您的网络根目录中获取一个。表单身份验证(和我的 web.config)锁定了我的根目录。从我的根目录提供的唯一文件是我的 loginUrl 页面。

每次发出 favicon.ico 的请求时,Forms Authentication 都不允许它并将请求重定向到我的 loginUrl 页面,因此导致我的 loginUrl 页面被执行 两次 搞砸了我的会话值。以下 Fiddler 屏幕截图显示了证据。

Chrome 似乎在每次页面请求时都请求图标:

而 Firefox 似乎最初请求它两次,出于某种原因,但随后放弃了后续请求:

所以,解决方案:

  1. 创建一个 favicon.ico 文件并将其放在您的网站根目录中。
  2. 允许通过根 web.config.

    中的 <location> 元素匿名访问它
    <location path="favicon.ico">
        <system.web>
            <authorization>
                <allow users="?" />
            </authorization> 
        </system.web>
    </location>
    

或者(可能是首选方法,因为您可以指定名称和位置):

  1. 创建一个 favicon.ico 文件并将其放在 public 子文件夹中,例如 /img.
  2. <link> 在您的 loginUrl 页面中正确添加。

    <link rel="icon" href="/img/favicon.ico">