使用AngularJS和PHP创建跨子域cookie/session

3
我的应用程序具有以下结构:前端JS应用程序(Angular)位于app.子域上,后端(PHP)位于根目录和api.子域上。我的登录是通过根目录完成的,该目录存储会话cookie。该Cookie存储在所有子域中,路径为“/”。
直接在API上,我可以获取Cookie。但是,在使用来自前端的Ajax GET调用的相同URL时,Cookie为空。
但是,使用像Postman(Chrome应用)这样的应用程序对同一URL进行GET请求,我可以获取Cookie。因此,似乎这是特定于我的应用程序前端的问题。
以下是我的Angular应用程序的设置。我已在我的应用程序配置中设置了这些默认值:
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.withCredentials = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];

我已经在Chrome和FF上测试过了,但无法理解为什么我的前端和后端之间无法使用我的cookies/sessions。
更新20/11/2013:
我还遇到了一个特定的问题,与我使用的Angular版本有关。因为我正在使用`$resource`而不是只是`$http`,所以那个版本的angular在使用`$resource`时没有将`withCredentials`设置附加到http请求中。更新到最新的angularjs版本已经解决了我的问题。由于`withCredentials`没有被设置,我的cookies没有随着xhr请求一起发送。很可笑的是,我没有检查cookie是否被发送。

你在API中使用过setCookie()函数的domain参数吗? - Deniz Zoeteman
我正在使用Laravel 4。在我的配置中,我已将其设置为所有子域和路径为“/”。 - iamjonesy
你考虑过使用HTML5的浏览器本地存储代替Cookie吗? - Dave
还有一个问题是,当进行身份验证时,我的会话没有被持久化。也就是说,我已经登录了,但是从前端通过ajax调用访问时却没有登录。 - iamjonesy
你确定你的服务器端CORS配置正确吗?展示GET(以及OPTIONS)请求的所有请求和响应头。仔细查看“Access-Control-…”头部。 - Adam
@iamjonesy,我猜你的问题现在已经得到关注了 :) 只需检查我的答案即可。 - Anshu Dwibhashi
2个回答

5
withCredentials属性不足以使它正常工作。服务器响应必须具有Access-Control-Allow-Credentials: true头信息。

您还应检查Access-Control-Request-HeadersAccess-Control-Allow-Headers以及其他请求和响应中的Access-Control-...头信息,并确保服务器正确处理OPTIONS方法请求和所有CORS头信息。

另请参见:http://www.html5rocks.com/en/tutorials/cors/


谢谢,之前在服务器上没有设置凭据设置。另外,请查看我对问题的更新,我遇到了一个关于Angular未能使用$resource http包装器设置withCredentials配置设置的问题。 - iamjonesy
@iamjonesy 你之前使用的是哪个版本? - Adam

4

Cookie可见性 - 解释

下面是一个有效的cookie设置头部的例子:

Set-Cookie: name=Anshuman; Domain=www.stronia.com; Path=/

现在,让我解释一下上面这行的含义。

Path:

Path=/ 是cookie可见性的默认路径,因此它与不指定任何路径相同。

当我们说路径将是 / 时,我们的意思是所有路径都是 / 路径的子级,可以访问该cookie。 因此,/foo 将能够访问cookie,/foo/bar 将能够访问cookie,/foo/bar/...../anything 也将能够访问cookie,因为它们都是路径 / 的子级。

假设所提到的路径是 /mypath。请注意,所提到路径的父级(如 /)或兄弟(如 /myotherpath)或兄弟的子级(如 /myotherpath/a/b/c)都无法访问该cookie。

只有所提到的路径及其子级可以访问该cookie。

简而言之,任何以所提到的路径开头的路径都将从浏览器接收cookie。

Domain:

当我们说域将是 www.stronia.com 时,我们的意思是所有域都是域 www.stronia.com 的子级,可以访问该cookie。 因此,foo.www.stronia.com 将获得访问cookie的权限,bar.foo.stronia.com 将获得访问cookie的权限,anything.....bar.foo.stronia.com 也将获得访问cookie的权限,因为上述所有域都是指定域:www.stronia.com 的子级。

但请注意,所提到的域的父级(如 stronia.com.com)或兄弟(如 sib.stronia.com)或兄弟的子级(如 a.b.c.d.sib.stronia.com)都无法访问该cookie。

只有所提到的域及其子级可以访问该cookie。

简而言之,任何以所提到的域结尾的域都将从浏览器接收cookie。


您的问题 - 解决方案

现在,在您的情况下,您希望应用程序的子域和api的子域共享cookie。 所以,您只需使用我上面提到的规则设置cookie,以便两个子域都可以接收。

因此,在PHP代码中,假设您的域名是 yourdomain.com

setcookie ("CookieName", "CookieValue", $expirationtime , "/", "yourdomain.com");

在Laravel4中:
put( 'CookieName','CookieValue', $expirationtime, '/', 'yourdomain.com');

如果您这样做,您的cookie将对app.yourdomain.comapi.yourdomain.com都可见。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接