单页应用程序丢失身份验证令牌 cookie
Single page application losing authentication token cookie
提前为下面的文字墙道歉,但我想确保在日志中包含任何可能有用的内容....
我有一个 ASP.Net MVC 应用程序,其主要界面是使用 SignalR 的单页应用程序。我们偶尔会遇到用户突然 "not working" 的问题——根本原因是他们不再经过身份验证。我每分钟都有一个 MVC 请求来保持会话活动,SignalR 每 5 分钟也有自己的保持活动状态。它似乎与特定的时间间隔无关,因为大多数时候,用户整天打开应用程序都没有问题。我在下面的 Web 服务器上包含了带注释的 IIS 日志示例。为了便于阅读,身份验证令牌和会话值已缩短。请注意,身份验证令牌已多次更新,没有任何问题。然后,突然之间,浏览器不再发送身份验证令牌。
+------------+----------+-----------+------------------------------+-------------+-------------------------------------+-----------+------------------------------------------------------------------------------------------------+
| date | time | cs-method | cs-uri-stem | cs-username | cs(Cookie) | sc-status | comment |
+------------+----------+-----------+------------------------------+-------------+-------------------------------------+-----------+------------------------------------------------------------------------------------------------+
| 2015-11-04 | 10:54:30 | GET | / | - | - | 302 | user requesting page for the first time; redirect to login page |
| 2015-11-04 | 10:54:30 | GET | /Account/Login | - | - | 200 | login page GET |
| 2015-11-04 | 10:54:46 | POST | /Account/Login | - | | 302 | login page POST; authenticate and redirect to content page |
| 2015-11-04 | 10:54:46 | GET | / | user123 | .VWRID=AAAA | 302 | content page GET; user is logged in |
| 2015-11-04 | 10:54:46 | GET | /Account/SelectConfiguration | user123 | .VWRID=AAAA | 200 | user doing stuff; no problem |
| 2015-11-04 | … | … | … | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | user doing stuff; no problem |
| 2015-11-04 | 10:54:50 | GET | /signalr/negotiate | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | SignalR connection |
| 2015-11-04 | 10:54:50 | GET | /signalr/start | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 10:54:50 | POST | /signalr/send | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 10:55:50 | POST | /Home/CheckVersion | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | keepalive for ASP.Net session; once/min |
| 2015-11-04 | … | … | … | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | user doing stuff; no problem |
| 2015-11-04 | 10:59:50 | GET | /signalr/ping | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | SignalR keepalive; once/5 min |
| 2015-11-04 | 11:00:50 | … | … | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:08:50 | POST | /Home/CheckVersion | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:09:50 | POST | /Home/CheckVersion | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | renewed ASP.net token sent to client (?) |
| 2015-11-04 | 11:09:50 | GET | /signalr/ping | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | new ASP.net token sent to server |
| 2015-11-04 | 11:10:50 | POST | /Home/CheckVersion | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:11:50 | POST | /Home/CheckVersion | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | … | … | … | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | user doing stuff; no problem |
| 2015-11-04 | 11:24:32 | POST | /signalr/send | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:24:50 | POST | /Home/CheckVersion | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | renewed ASP.net token sent to client (?) |
| 2015-11-04 | 11:24:50 | GET | /signalr/ping | user123 | .VWRID=CCCC;+ASP.NET_SessionId=ses1 | 200 | new ASP.net token sent to server |
| 2015-11-04 | 11:25:50 | POST | /Home/CheckVersion | user123 | .VWRID=CCCC;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | … | … | … | user123 | .VWRID=CCCC;+ASP.NET_SessionId=ses1 | 200 | user doing stuff; no problem |
| 2015-11-04 | … | … | … | user123 | .VWRID=CCCC;+ASP.NET_SessionId=ses1 | 200 | same pattern continues, until… |
| 2015-11-04 | 11:58:50 | POST | /Home/CheckVersion | user123 | .VWRID=EEEE;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:59:50 | POST | /Home/CheckVersion | user123 | .VWRID=EEEE;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:59:50 | GET | /signalr/ping | user123 | .VWRID=EEEE;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 12:00:50 | POST | /Home/CheckVersion | - | - | 302 | NO AUTHENTICATION COOKIE! |
| 2015-11-04 | 12:00:50 | GET | /Account/Login | - | - | 200 | JSON request "redirected" but user never notified |
| 2015-11-04 | 12:01:50 | POST | /Home/CheckVersion | - | | 302 | |
| 2015-11-04 | 12:01:50 | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | … | POST | /Home/CheckVersion | - | | 302 | same pattern… |
| 2015-11-04 | … | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | 12:04:49 | GET | /signalr/ping | - | | 200 | signalr keepalive returns HTTP 200 (?)… |
| 2015-11-04 | 12:05:50 | POST | /Home/CheckVersion | - | | 302 | |
| 2015-11-04 | 12:05:50 | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | … | POST | /Home/CheckVersion | - | | 302 | |
| 2015-11-04 | … | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | 12:16:43 | POST | /signalr/send | - | | 403 | … but signalr requests fail because they need to be authenticated |
| 2015-11-04 | … | POST | /signalr/send | - | | 403 | |
| 2015-11-04 | 12:43:23 | POST | /signalr/abort | - | | 403 | at some point signalr aborts |
| 2015-11-04 | 12:43:23 | GET | /signalr/connect | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | and reconnects with the ORIGINAL authentication token (?) |
| 2015-11-04 | 12:43:23 | GET | / | - | | 302 | User realizes there is a problem and refreshed the page, forcing the login process to initiate |
| 2015-11-04 | 12:43:23 | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | 12:43:35 | POST | /Account/Login | - | | 302 | |
| 2015-11-04 | 12:43:35 | GET | / | user123 | .VWRID=FFFF | 302 | and we're good again… |
| 2015-11-04 | 12:43:36 | GET | /Account/SelectConfiguration | user123 | .VWRID=FFFF | 200 | |
| 2015-11-04 | … | … | … | user123 | .VWRID=FFFF;+ASP.NET_SessionId=ses2 | 200 | |
| 2015-11-04 | 15:43:02 | POST | /Home/CheckVersion | user123 | .VWRID=GGGG;+ASP.NET_SessionId=ses2 | 200 | still going strong nearly 2 hours later. |
+------------+----------+-----------+------------------------------+-------------+-------------------------------------+-----------+------------------------------------------------------------------------------------------------+
web.config的相关部分:
<system.web>
<authentication mode="Forms">
<forms name=".VWRID" loginUrl="~/Account/Login" timeout="30" slidingExpiration="true" protection="All" requireSSL="true" />
</authentication>
</system.web>
有没有人知道这里可能发生了什么以及如何解决?
[更新]
查看日志,这似乎只影响 IE 10 上的用户。那里使用的 SignalR 传输机制是 foreverFrame。我想知道这是否是该传输的 SignalR 错误。我打算将这些客户端降级为使用长轮询,看看问题是否消失。
我们删除了 SignalR 传输的 foreverFrame 选项,问题就消失了。似乎是 SignalR 中的错误。
提前为下面的文字墙道歉,但我想确保在日志中包含任何可能有用的内容....
我有一个 ASP.Net MVC 应用程序,其主要界面是使用 SignalR 的单页应用程序。我们偶尔会遇到用户突然 "not working" 的问题——根本原因是他们不再经过身份验证。我每分钟都有一个 MVC 请求来保持会话活动,SignalR 每 5 分钟也有自己的保持活动状态。它似乎与特定的时间间隔无关,因为大多数时候,用户整天打开应用程序都没有问题。我在下面的 Web 服务器上包含了带注释的 IIS 日志示例。为了便于阅读,身份验证令牌和会话值已缩短。请注意,身份验证令牌已多次更新,没有任何问题。然后,突然之间,浏览器不再发送身份验证令牌。
+------------+----------+-----------+------------------------------+-------------+-------------------------------------+-----------+------------------------------------------------------------------------------------------------+
| date | time | cs-method | cs-uri-stem | cs-username | cs(Cookie) | sc-status | comment |
+------------+----------+-----------+------------------------------+-------------+-------------------------------------+-----------+------------------------------------------------------------------------------------------------+
| 2015-11-04 | 10:54:30 | GET | / | - | - | 302 | user requesting page for the first time; redirect to login page |
| 2015-11-04 | 10:54:30 | GET | /Account/Login | - | - | 200 | login page GET |
| 2015-11-04 | 10:54:46 | POST | /Account/Login | - | | 302 | login page POST; authenticate and redirect to content page |
| 2015-11-04 | 10:54:46 | GET | / | user123 | .VWRID=AAAA | 302 | content page GET; user is logged in |
| 2015-11-04 | 10:54:46 | GET | /Account/SelectConfiguration | user123 | .VWRID=AAAA | 200 | user doing stuff; no problem |
| 2015-11-04 | … | … | … | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | user doing stuff; no problem |
| 2015-11-04 | 10:54:50 | GET | /signalr/negotiate | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | SignalR connection |
| 2015-11-04 | 10:54:50 | GET | /signalr/start | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 10:54:50 | POST | /signalr/send | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 10:55:50 | POST | /Home/CheckVersion | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | keepalive for ASP.Net session; once/min |
| 2015-11-04 | … | … | … | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | user doing stuff; no problem |
| 2015-11-04 | 10:59:50 | GET | /signalr/ping | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | SignalR keepalive; once/5 min |
| 2015-11-04 | 11:00:50 | … | … | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:08:50 | POST | /Home/CheckVersion | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:09:50 | POST | /Home/CheckVersion | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | renewed ASP.net token sent to client (?) |
| 2015-11-04 | 11:09:50 | GET | /signalr/ping | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | new ASP.net token sent to server |
| 2015-11-04 | 11:10:50 | POST | /Home/CheckVersion | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:11:50 | POST | /Home/CheckVersion | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | … | … | … | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | user doing stuff; no problem |
| 2015-11-04 | 11:24:32 | POST | /signalr/send | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:24:50 | POST | /Home/CheckVersion | user123 | .VWRID=BBBB;+ASP.NET_SessionId=ses1 | 200 | renewed ASP.net token sent to client (?) |
| 2015-11-04 | 11:24:50 | GET | /signalr/ping | user123 | .VWRID=CCCC;+ASP.NET_SessionId=ses1 | 200 | new ASP.net token sent to server |
| 2015-11-04 | 11:25:50 | POST | /Home/CheckVersion | user123 | .VWRID=CCCC;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | … | … | … | user123 | .VWRID=CCCC;+ASP.NET_SessionId=ses1 | 200 | user doing stuff; no problem |
| 2015-11-04 | … | … | … | user123 | .VWRID=CCCC;+ASP.NET_SessionId=ses1 | 200 | same pattern continues, until… |
| 2015-11-04 | 11:58:50 | POST | /Home/CheckVersion | user123 | .VWRID=EEEE;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:59:50 | POST | /Home/CheckVersion | user123 | .VWRID=EEEE;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 11:59:50 | GET | /signalr/ping | user123 | .VWRID=EEEE;+ASP.NET_SessionId=ses1 | 200 | |
| 2015-11-04 | 12:00:50 | POST | /Home/CheckVersion | - | - | 302 | NO AUTHENTICATION COOKIE! |
| 2015-11-04 | 12:00:50 | GET | /Account/Login | - | - | 200 | JSON request "redirected" but user never notified |
| 2015-11-04 | 12:01:50 | POST | /Home/CheckVersion | - | | 302 | |
| 2015-11-04 | 12:01:50 | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | … | POST | /Home/CheckVersion | - | | 302 | same pattern… |
| 2015-11-04 | … | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | 12:04:49 | GET | /signalr/ping | - | | 200 | signalr keepalive returns HTTP 200 (?)… |
| 2015-11-04 | 12:05:50 | POST | /Home/CheckVersion | - | | 302 | |
| 2015-11-04 | 12:05:50 | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | … | POST | /Home/CheckVersion | - | | 302 | |
| 2015-11-04 | … | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | 12:16:43 | POST | /signalr/send | - | | 403 | … but signalr requests fail because they need to be authenticated |
| 2015-11-04 | … | POST | /signalr/send | - | | 403 | |
| 2015-11-04 | 12:43:23 | POST | /signalr/abort | - | | 403 | at some point signalr aborts |
| 2015-11-04 | 12:43:23 | GET | /signalr/connect | user123 | .VWRID=AAAA;+ASP.NET_SessionId=ses1 | 200 | and reconnects with the ORIGINAL authentication token (?) |
| 2015-11-04 | 12:43:23 | GET | / | - | | 302 | User realizes there is a problem and refreshed the page, forcing the login process to initiate |
| 2015-11-04 | 12:43:23 | GET | /Account/Login | - | | 200 | |
| 2015-11-04 | 12:43:35 | POST | /Account/Login | - | | 302 | |
| 2015-11-04 | 12:43:35 | GET | / | user123 | .VWRID=FFFF | 302 | and we're good again… |
| 2015-11-04 | 12:43:36 | GET | /Account/SelectConfiguration | user123 | .VWRID=FFFF | 200 | |
| 2015-11-04 | … | … | … | user123 | .VWRID=FFFF;+ASP.NET_SessionId=ses2 | 200 | |
| 2015-11-04 | 15:43:02 | POST | /Home/CheckVersion | user123 | .VWRID=GGGG;+ASP.NET_SessionId=ses2 | 200 | still going strong nearly 2 hours later. |
+------------+----------+-----------+------------------------------+-------------+-------------------------------------+-----------+------------------------------------------------------------------------------------------------+
web.config的相关部分:
<system.web>
<authentication mode="Forms">
<forms name=".VWRID" loginUrl="~/Account/Login" timeout="30" slidingExpiration="true" protection="All" requireSSL="true" />
</authentication>
</system.web>
有没有人知道这里可能发生了什么以及如何解决?
[更新]
查看日志,这似乎只影响 IE 10 上的用户。那里使用的 SignalR 传输机制是 foreverFrame。我想知道这是否是该传输的 SignalR 错误。我打算将这些客户端降级为使用长轮询,看看问题是否消失。
我们删除了 SignalR 传输的 foreverFrame 选项,问题就消失了。似乎是 SignalR 中的错误。