AngularJS将忽略HTTP标头中的Set-Cookie


67

我正在基于客户端的AngularJS和基于Java的服务器的Java(Tomcat + WS的Jersey)开发应用程序。

我的API的某些路径受到限制,如果用户没有会话,则返回的响应状态为401。在客户端,将拦截401 http状态以将用户重定向到登录页面。

用户通过身份验证后,我将在服务器端创建一个会话

httpRequest.getSession(true);
并且发送给客户端的响应的标头中确实包含Set-cookie指令:

Set-Cookie:JSESSIONID = XXXXXXXXXXXXXXXXXXXXX; 域=本地主机; 路径= / api /; HttpOnly

问题是cookie永远不会放在客户端。当我检查本地域的cookie时,它为空,因此下一个请求的标头中没有此cookie,并且客户端仍然无法访问我的API的受限路径。

客户端和服务器位于同一个域中,但是它们没有相同的路径和端口号:

客户: http://localhost:8000/app/index.html

服务器: http://localhost:8080/api/restricted/

附加信息:双方都启用了CORS:

“访问控制允许方法”,“获取,发布,选项”
“访问控制允许来源”,“ *”
“访问控制允许凭据”,true

有任何使Set-cookie正常工作的想法吗?这是与AngularJS相关的问题吗?


我不确定它是否仍然有用,但是让您的API依赖状态是一个错误的设计选择(tm)。您应该将API设为无状态,以避免将来出现问题。
sberder

Answers:


21

在AngularJS中发现了一个问题,可以帮助我继续前进。

似乎"Access-Control-Allow-Credentials" : true没有在客户端设置。指令$httpProvider.defaults.withCredentials = true 被忽略。

我用config参数中的{withCredentials:true}用一个简单的$ http调用替换$ resource调用。


3
如果您想出解决方案,别忘了发布答案。如果您的客户端是移动客户端,并且您正在使用phonegap / cordova或本机客户端,则是否尝试覆盖Origin / Refferer标头并使用恒定原点?
Ovidiu Buligan

1
您可以在后端获取来源,然后发送相关的标头。这是一个express.js示例:var origin = req.headers.origin; res.header('Access-Control-Allow-Origin',origin);
劳里斯2014年

您似乎同时发布了一个答案和一个问题作为答案。要提出新问题,请使用页面顶部的“问问题”按钮。如果它有助于提供上下文,则可以链接到此问题。
elixenide

1
当“ Access-Control-Allow-Credentials”为true时,必须为“ Access-Control-Allow-Origin”,“”显式返回正确的域。不允许使用星号。因此,人们具有多个允许的来源的方法是让一个函数拦截请求的来源,进行验证(如果此来源位于您的允许列表中),然后在“ Access-Control-Allow-Origin”中设置请求的来源。例如,我想让localhost和example.com工作。因此,当从本地主机发出请求时,我的标头必须为“ Access-Control-Allow-Origin”,“ localhost”,例如example.com“ Access-Control-Allow-Origin”,“ example.com”
Jan Weitz

18

我设法解决了一个与您非常相似的问题。我的玩!后端试图设置一个会话Cookie,我无法在Angular中捕获它,也无法通过浏览器存储它。

实际上,解决方案涉及到这一点。

假设您已经解决了最初的问题,那么只能通过将特定域添加到Access-Control-Allow-Origin并删除通配符来解决此问题,接下来的步骤是:

  1. 您必须从Set-Cookie标头中删除仅HTTP ,否则您将永远无法收到由角度代码“生成”的cookie。
    此设置已在Firefox中运行,但在Chrome中不起作用

  2. 要使其也适用于Chrome,您需要:

    a)使用WS被“托管”的域,从cookie中的localhost发送一个不同的域。您甚至可以使用通配符(例如).domain.com代替ws.domain.com

    b)那么您需要致电您在Cookie中指定的域,否则Chrome不会存储您的Cookie

    [可选]我会删除该/api路径,而采用/


那应该是把戏。
希望能有所帮助


我认为问题在于路径是/ api,应该是/
Seth M.

1
当您说“发送与Cookie中的localhost不同的域时,使用您的WS被“托管”的域”是指前端主机还是后端主机?
Pathsofdesign 2014年

通常它应该是您的后端,但是它实际上取决于您的服务器体系结构。您不知道您的WS在哪里吗?
domokun 2014年

14

在客户端的发帖请求中,请确保添加以下内容:

对于jquery ajax请求:

$.ajax({
  url: "http://yoururlgoeshere",
  type: "post",
  data: "somedata",
  xhrFields: {
    withCredentials: true
  }
});

使用Angular的$ http服务:

$http.post("http://yoururlgoeshere", "somedata", {
  withCredentials: true
});


在我的案例中,我发现xhrFields:{...}引起了一些问题(我的服务器响应了诸如unknow origin *之类的内容),所以我改用了beforeSend: function(xhr){ xhr.withCredentials = true; } 它,并且工作正常
medBouzid

我花了一天多的时间才意识到,withCredentials = true它不仅告诉浏览器根据请求附加cookie,而且告诉它根据响应设置新的cookie。fetch函数的ajax选项与此相同,credentials: 'include'必须使用该选项才能使浏览器根据请求和响应发送和设置cookie。
0xC0DEGURU '04

9

您需要在服务器端和客户端上工作。

客户

通过以下方式之一将$httpconfig设置withCredentialstrue

  1. 根据要求

    var config = {withCredentials: true};
    $http.post(url, config);
    
  2. 对于所有要求

    angular.module("your_module_name").config(['$httpProvider',
      function($httpProvider) {
        $httpProvider.interceptors.push(['$q',
          function($q) {
            return {
              request: function(config) {
                config.withCredentials = true;
                return config;
              }
            };
          }
        ]);
      }
    ]);
    

服务器

将响应标头设置Access-Control-Allow-Credentialstrue


2
无需创建拦截器,现在您可以使用它$httpProvider.defaults.withCredentials = true;
vs4vijay 2015年

我花了一天多的时间才意识到,withCredentials = true它不仅告诉浏览器根据请求附加cookie,而且告诉它根据响应设置新的cookie。fetch函数的ajax选项与此相同,credentials: 'include'必须使用该选项才能使浏览器根据请求和响应发送和设置cookie。即,当将loginajax请求发送到专用api时,尽管不需要cookie,但withCredentials=true必须设置该sessionidcookie,否则接收到的cookie将可用,但浏览器不会保存它。
0xC0DEGURU '04

7

HttpOnly的添加意味着浏览器不应让插件和JavaScript看到cookie。这是最近的安全浏览惯例。应该用于J_SESSIONID,但可能不在这里。


即使不存在HttpOnly属性,仍不会在客户端上设置cookie。
罗曼·勒弗朗索瓦

你确定吗?它是用于/ api /的会话cookie 。一种实验是使用response.encodeURL您的链接。然后,第一个答案可能仍使用“ ...?JSESSIONID = ...”代替cookie。但是后续调用应设置cookie。您在浏览器中查找过Cookie吗?
Joop Eggen

是的,当我使用Chrome浏览器查看cookie是否已在浏览器中设置和/或是否出现在请求和响应标头中时。Cookie是“仅会话”,是。
Romain Lefrancois

我不知道是否未设置localhost / api的cookie。您可以尝试删除HttpOnly(会很有趣),或者将cookie设置为localhost /而不是localhost / api(不太可能)。
Joop Eggen

1
同时删除安全;(如果显示的话)来自Set-Cookie,如果您希望浏览器能够在后续的XHR调用中存储和使用cookie。
大卫

2

刚刚解决了这样的问题。

我正在这样做,但不起作用...:

  $cookies.put('JSESSIONID', response.data);

Cookies被保存在浏览器中,但是当我发送新请求时,所有cookie都是我的。(我的cookie是JSESSIONID)

然后我看了看铬检查器,发现了这一点: 我的会话是JsessionID

问题不是正确的途径!!!

然后我尝试了此操作,并发送了我的cookie。好极了!:

$cookies.put('JSESSIONID', response.data, {'path':'/'});

我不知道这是否是您的情况,但这对我有用。

问候!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.