前段时间在项目里遇到了一个比较头疼的问题,就是高版本的Safari中默认会阻止第三方cookie,这使得使用Safari浏览器的用户无法按照正常的业务逻辑进行操作。
问题展现
知识点
什么是第三方cookie呢?在访问一个网站A时,网站A算作第一方,如果网站A中引用了另一个网站B(网站B的域名与网站A的域名不同)的资源,这时这个网站B就被认为是第三方。需要注意的是,这儿区分不同网站的标准是域名是否相同,而不是这两个网站是否由同一个公司运营。比如,taobao.com和tmall.com被认为是两个网站,尽管它们都属于阿里集团。
问题demo
仅供参考,新建两个basic MVC项目CookieSolution和TestCookieSolution。假设CookieSolution里面是正常的业务逻辑,有两个页面Page1 和Page2 ,相应代码如下:
public ActionResult Page1()
{
Session["mySession"] = "Jackbase";
return View();
} public ActionResult Page2()
{
if (Session["mySession"] != "Jackbase")
{
return Redirect("Page1");
}
return View();
}
后台代码如上,前台代码如下:
@*Page1的前台代码*@
<h2>Page 1</h2> <a href="/Home/Page2">Go to Page 2</a> @*Page2的前台代码*@
<h2>Page 2</h2> <a href="/Home/Page1">Back to Page 1</a>
可以看出在Page1的初始化里设置Session["mySession"]的值,在Page2的初始化里检测Session["mySession"]的值,如果值不对,则跳回Page1。在TestCookieSolution中的页面里用iframe引用CookieSolution的页面,前台代码如下:
<h2>Test</h2> <iframe src="http://www.cookieSolution.com"></iframe>
后台
public ActionResult Test()
{
return View();
}
不要问我www.cookieSolution.com是什么,自行在hosts里添加。
127.0.0.1 www.cookieSolution.com
一切准备就绪,在IIS里面新建两个站点,分别绑定CookieSolution(80端口)和TestCookieSolution(8050端口)
访问http://localhost:8050进行测试(基于Safari浏览器),发现点击Go to Page2完全不能跳到Page2中,依然在Page1 中。Safari安全机制阻止了第三方的Cookie以及Session,网上有很多方法我都做了一一尝试,什么P3P几乎完全不行...
解决方案
既然浏览器阻止的是第三方Cookie及数据,那么我们就想办法让浏览器认为iframe中的页面不属于第三方不就行了吗?那么我们在进入Test页面之前先打开www.cookieSolution.com中的一个页面,设置cookie,然后再跳转到Test页面,这时www.cookieSolution.com就不在属于第三方了。
在TestCookieSolution新增一个页面,PreTest.
public ActionResult PreTest()
{
return View();
}
<h2>PreTest</h2> <a href="http://www.cookieSolution.com/Home/CookieMaker?url=http://localhost:8050/Home/Test">Go to Test</a>
在CookieSolution的HomeController里面新增方法
public ActionResult CookieMaker()
{
// 随意设置一个Session
Session["Prepare"] = "jb";
return Redirect(Request.QueryString["url"]);
}
这样就解决了这个难题了,有兴趣的同学可自行测试,这里就不过多演示了。
参考资料
Missing cookies on iframe in safari 5.1.5
Safari 3rd party cookie iframe trick no longer working?
Ipad Safari iframe cookie 当浏览器默认禁用第三方COOKIE
本文所用代码demo