在iOS Safari上的浏览器会话之间未保存Cookie

时间:2022-09-15 10:40:56

I have an MVC 4 website where a user can login and I save a cookie with their session information so they don't have to login again.

我有一个MVC 4网站,用户可以登录,我用他们的会话信息保存一个cookie,这样他们就不必再次登录了。

public void SetCookie(HttpCookie cookie)
{
    HttpContext.Current.Response.Cookies.Set(cookie);
}

This works on desktop devices, but when I run this on iOS, it doesn't work 100% of the time. If I leave at least 1 page open in the mobile browser (either Chrome or Safari), and navigate back to my site, my session cookie is found and I don't have to login. But if I close ALL windows of that browser, then the next time I navigate back to my site, the session cookie is not found. I'm setting a 1 year duration/expiration on my cookie so it's not expiring.

这适用于桌面设备,但是当我在iOS上运行它时,它在100%的时间内都不起作用。如果我在移动浏览器(Chrome或Safari)中打开至少1页,并导航回我的网站,则会找到我的会话cookie,而我无需登录。但是,如果我关闭该浏览器的所有窗口,那么下次我导航回我的网站时,找不到会话cookie。我在我的cookie上设置了1年的持续时间/到期时间,因此它没有到期。

The only thing I've found so far is that this is a bug in .NET 4.0 and is fixed in .NET 4.5. I believe I'm already running .NET 4.5, by looking at my *.csproj and the TargetFrameworkVersion element:

到目前为止,我唯一发现的是这是.NET 4.0中的一个错误,并在.NET 4.5中得到修复。我相信我已经在运行.NET 4.5了,看看我的* .csproj和TargetFrameworkVersion元素:

<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>
    </ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{xxxxxxxxxxxxxxxxxx}</ProjectGuid>
    <ProjectTypeGuids>{xxxxxxxx};{xxxxxxxxxxxxx};{xxxxxxxxxxxxxxxx}</ProjectTypeGuids>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>MyApp</RootNamespace>
    <AssemblyName>MyApp</AssemblyName>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <MvcBuildViews>false</MvcBuildViews>
    <UseIISExpress>true</UseIISExpress>
    <IISExpressSSLPort />
    <IISExpressAnonymousAuthentication />
    <IISExpressWindowsAuthentication />
    <IISExpressUseClassicPipelineMode />
  </PropertyGroup>

Is this a bug with .NET (or MVC), or is it my coding? Do I need to upgrade to MVC 5 (instead of the original recommendation of upgrading to .NET 4.5)?

这是.NET(或MVC)的错误,还是我的编码?我是否需要升级到MVC 5(而不是升级到.NET 4.5的原始建议)?

This has really been bugging me since the majority of the traffic to my site in the next coming months will be from mobile users, and I'll probably lose some of them if they have to keep logging in everytime (I know I hate having to login on a mobile device...)

这真的让我烦恼,因为未来几个月我的网站的大部分流量将来自移动用户,如果他们每次都必须继续登录,我可能会失去一些(我知道我讨厌必须在移动设备上登录...)

Edit:

编辑:

Btw - Here's another page on the same subject: Asp.Net Forms Authentication when using iPhone UIWebView

顺便说一下 - 这是关于同一主题的另一个页面:使用iPhone UIWebView时的Asp.Net Forms身份验证

And I've also tried implementing this and it didn't work either:

而且我也试过实现这个,它也没有用:

http://www.bloggersworld.com/index.php/asp-net-forms-authentication-iphone-cookies/

http://www.bloggersworld.com/index.php/asp-net-forms-authentication-iphone-cookies/

And the above includes Scott Hanselmans suggested fix:

以上包括Scott Hanselmans建议修复:

http://www.hanselman.com/blog/FormsAuthenticationOnASPNETSitesWithTheGoogleChromeBrowserOnIOS.aspx

http://www.hanselman.com/blog/FormsAuthenticationOnASPNETSitesWithTheGoogleChromeBrowserOnIOS.aspx

Here's my cookie creation code, in case it helps:

这是我的cookie创建代码,以防它有用:

private void CreateAndSetAuthenticationCookie(int loginId, string username)
    {
        HttpCookie cookie = CreateAuthenticationCookie(loginId, username);

        _cookieService.SetCookie(cookie);
    }

    private HttpCookie CreateAuthenticationCookie(int loginId, string username)
    {
        string userData = string.Format("loginId:{0},username:{1}", loginId, username);
        var ticket = new FormsAuthenticationTicket(loginId, username, DateTime.Now, DateTime.Now.AddYears(1), false, userData, FormsAuthentication.FormsCookiePath);
        string encryptedTicket = FormsAuthentication.Encrypt(ticket);

        return new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
    }

One thing that I pointed out in my comments, I have "PersistentCookie" set to false....not sure if that makes a difference, I'll do more research.

我在评论中指出的一件事是,我将“PersistentCookie”设置为假......不确定这是否有所作为,我会做更多的研究。

Update:

更新:

First of all, the PersistentCookie is set to true now, and that did not have any changes on the behavior.

首先,PersistentCookie现在设置为true,并且对行为没有任何更改。

One of the commentors below suggested that I run Fiddler while accessing the website from iPhone. After going through the very short and easy steps to get that setup, here's what I found out.

下面的评论之一表明我在从iPhone访问网站时运行Fiddler。经过非常简单的步骤来完成设置后,这就是我发现的。

The first request I tried pointed out (I believe) what the actual problem is. When I examined that first request, iOS Safari is sending a DNT header. Having no idea what that was, I looked it up and it's a "Do Not Track" header.

我试过的第一个请求指出(我相信)实际问题是什么。当我检查第一个请求时,iOS Safari正在发送DNT标头。不知道那是什么,我查了一下,这是一个“不跟踪”标题。

Next, I went and checked my Safari settings to turn that off. Guess what, it's already off. Why the hell is Safari (iOS) sending a DNT header when the setting (Settings -> Safari -> Do Not Track) is not set? Also, the Block Cookies, which is right below it, is set to "Never".

接下来,我去检查我的Safari设置以关闭它。猜猜看,它已经关闭了。当设置(设置 - > Safari - >不跟踪)设置没有设置时,为什么Safari(iOS)发送DNT标题呢?此外,位于其下方的Block Cookies设置为“从不”。

After getting frustrated with that, I went to check on Chrome for iOS to see if that still doesn't work. IT WORKS! From what I can tell, I'd close all tabs, try again, close all tabs, then kill the browser, and it still works. Hooray!

在对此感到沮丧之后,我去了Chrome for iOS查看是否仍然无效。有用!据我所知,我将关闭所有标签,再次尝试,关闭所有标签,然后终止浏览器,它仍然有效。万岁!

Now, I need to figure out why iOS Safari is sending the DNT header...

现在,我需要弄清楚为什么iOS Safari会发送DNT标头...

2 个解决方案

#1


17  

This is HORRIBLY embarrasing. I found out that I've had my iOS Safari browser in "Private Browsing Mode" FOR YEARS!

这是令人难以置信的尴尬。我发现我已经在“私人浏览模式”中使用了我的iOS Safari浏览器了!

I feel like my "Software Developer" job title needs removed for awhile. Sorry for wasting everyone's time.

我觉得我的“软件开发人员”职称需要删除一段时间。很抱歉浪费每个人的时间。

#2


2  

I think you answered your own question with persistent cookie. Regular cookies expire when the browser session ends (this is typically closing the browser). Persistent cookies have a date when they should be removed and can live across browser sessions.

我认为你用持久性cookie回答了你自己的问题。常规cookie在浏览器会话结束时到期(这通常是关闭浏览器)。持久性cookie具有应该被删除的日期,并且可以跨浏览器会话生存。

Your code should look something like this:

您的代码应如下所示:

private HttpCookie CreateAuthenticationCookie(int loginId, string username)
{
    string userData = string.Format("loginId:{0},username:{1}", loginId, username);
    var ticket = new FormsAuthenticationTicket(loginId, username, 
                         DateTime.Now, DateTime.Now.AddYears(1), 
                         false, userData, FormsAuthentication.FormsCookiePath);
    string encryptedTicket = FormsAuthentication.Encrypt(ticket);

    return new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket){{
         Expires = DateTime.Now.AddYears(1);
    }};
}

This way your cookie will persist across browser sessions for one year.

这样,您的cookie将在浏览器会话中保留一年。

#1


17  

This is HORRIBLY embarrasing. I found out that I've had my iOS Safari browser in "Private Browsing Mode" FOR YEARS!

这是令人难以置信的尴尬。我发现我已经在“私人浏览模式”中使用了我的iOS Safari浏览器了!

I feel like my "Software Developer" job title needs removed for awhile. Sorry for wasting everyone's time.

我觉得我的“软件开发人员”职称需要删除一段时间。很抱歉浪费每个人的时间。

#2


2  

I think you answered your own question with persistent cookie. Regular cookies expire when the browser session ends (this is typically closing the browser). Persistent cookies have a date when they should be removed and can live across browser sessions.

我认为你用持久性cookie回答了你自己的问题。常规cookie在浏览器会话结束时到期(这通常是关闭浏览器)。持久性cookie具有应该被删除的日期,并且可以跨浏览器会话生存。

Your code should look something like this:

您的代码应如下所示:

private HttpCookie CreateAuthenticationCookie(int loginId, string username)
{
    string userData = string.Format("loginId:{0},username:{1}", loginId, username);
    var ticket = new FormsAuthenticationTicket(loginId, username, 
                         DateTime.Now, DateTime.Now.AddYears(1), 
                         false, userData, FormsAuthentication.FormsCookiePath);
    string encryptedTicket = FormsAuthentication.Encrypt(ticket);

    return new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket){{
         Expires = DateTime.Now.AddYears(1);
    }};
}

This way your cookie will persist across browser sessions for one year.

这样,您的cookie将在浏览器会话中保留一年。