2013-02-22 30 views
64

Tôi đang làm việc trên một ứng dụng dựa trên AngularJS ở phía máy khách và Java cho API của tôi (Tomcat + Jersey cho WS) ở phía máy chủ.Đặt cookie trong tiêu đề HTTP bị bỏ qua với AngularJS

Một số đường dẫn API của tôi bị hạn chế, nếu người dùng không có phiên, trạng thái trả lời là 401. Về phía máy khách, trạng thái 401 http bị chặn để chuyển hướng người dùng đến trang đăng nhập.

Khi người dùng được xác thực, tôi tạo ra một phiên họp về phía máy chủ

httpRequest.getSession(true);
và đáp ứng gửi cho khách hàng không có hướng dẫn Set-cookie trong phần đầu của nó:

 
Set-Cookie:JSESSIONID=XXXXXXXXXXXXXXXXXXXXX; Domain=localhost; Path=/api/; HttpOnly 

Vấn đề là các cookie không bao giờ được đặt ở phía khách hàng. Khi tôi kiểm tra cookie cho miền localhost, nó sẽ trống, vì vậy các yêu cầu tiếp theo không có cookie này trong tiêu đề và phía máy khách của họ vẫn không thể truy cập vào đường dẫn bị hạn chế của API của tôi.

Client và máy chủ đang ở trên cùng một tên miền nhưng họ không có con đường cùng và số cổng tương tự:

Chủ đầu tư: http://localhost:8000/app/index.html

Server: http://localhost:8080/api/restricted/

Thông tin thêm: CORS được bật ở cả hai bên:

"Access-Control-Allow-Methods", "GET, POST, OPTIONS" 
"Access-Control-Allow-Origin", "*" 
"Access-Control-Allow-Credentials", true

Bất kỳ ý tưởng nào để đặt cookie thiết lập hoạt động bình thường? Đây có phải là vấn đề liên quan đến AngularJS không?

+0

Tôi không chắc nó vẫn có liên quan nhưng làm cho API của bạn dựa vào các trạng thái là một lựa chọn thiết kế tồi (tm). Bạn nên làm cho trạng thái API của bạn để tránh các vấn đề trong tương lai. – sberder

+2

Bạn có tìm thấy giải pháp cho điều này không? Tôi lại không phải vấn đề tương tự. – Pathsofdesign

Trả lời

7

Việc bổ sung HttpOnly có nghĩa là trình duyệt không được để plugin và JavaScript xem cookie. Đây là một quy ước gần đây để duyệt bảo mật. Nên được sử dụng cho J_SESSIONID nhưng có thể không được sử dụng ở đây.

+0

Ngay cả khi thuộc tính HttpOnly không có, cookie vẫn chưa được đặt ở phía máy khách. –

+0

Bạn có chắc chắn không? Đây là cookie ** chỉ dành cho phiên ** cho **/api/**. Một thử nghiệm là sử dụng 'response.encodeURL' cho các liên kết của bạn. Câu trả lời đầu tiên có thể vẫn sử dụng "...? JSESSIONID = ..." thay vì cookie. Nhưng các cuộc gọi tiếp theo phải có tập hợp cookie. Bạn có tìm trong trình duyệt cookie không? –

+0

Có, khi tôi sử dụng Chrome để xem liệu cookie có được đặt trong trình duyệt và/hoặc có trong tiêu đề yêu cầu và phản hồi hay không. Cookie là Phiên chỉ có. –

20

Tôi đã tìm thấy issue in AngularJS giúp tôi tiến lên phía trước.

Dường như "Access-Control-Allow-Credentials" : true không được đặt ở phía máy khách. Hướng dẫn $httpProvider.defaults.withCredentials = true bị bỏ qua.

Tôi thay thế $ gọi tài nguyên bằng lệnh $ http đơn giản với {withCredentials: true} trong thông số cấu hình.

+3

Đừng quên đăng câu trả lời nếu bạn đã tìm ra giải pháp của mình. Nếu khách hàng của bạn là thiết bị di động và bạn đang sử dụng phonegap/cordova hoặc một khách hàng gốc, bạn có cố gắng ghi đè lên các tiêu đề gốc/refferer và sử dụng nguồn gốc không đổi không? –

+1

Bạn có thể lấy nguồn gốc trong phần phụ trợ của bạn và sau đó gửi một tiêu đề có liên quan. Dưới đây là ví dụ về express.js: var origin = req.headers.origin; res.header ('Access-Control-Allow-Origin', xuất xứ); – Lauris

+5

Đây không phải là giải pháp, mà là một câu hỏi ... –

17

Tôi đã cố gắng giải quyết một vấn đề rất giống với vấn đề của bạn. Phát của tôi! backend đã cố gắng để thiết lập một phiên Cookie mà tôi không thể bắt trong Angular hoặc lưu trữ thông qua trình duyệt.

Thực ra giải pháp có liên quan đến một chút điều này và một chút về điều đó.

Giả sử bạn đã giải quyết được vấn đề ban đầu, có thể được giải quyết chỉ bằng cách thêm một miền cụ thể đối với Access-Control-Allow-Origin và loại bỏ các ký tự đại diện, các bước tiếp theo là:

  1. bạn cần phải loại bỏ các HTTP-Chỉ từ Set-Cookie tiêu đề, nếu không bạn sẽ không bao giờ có thể nhận được một cookie "tạo ra" theo mã góc của bạn
    thiết lập này sẽ đã làm việc trong Firefox, mặc dù không phải trong Chrome

  2. Để làm cho nó hoạt động cho Chrome, bạn cần phải:

    a) gửi tên miền khác từ máy chủ cục bộ trong cookie, sử dụng tên miền mà WS của bạn được "lưu trữ". Bạn thậm chí có thể sử dụng ký tự đại diện như .domain.com thay vì ws.domain.com

    b) sau đó bạn sẽ cần phải thực hiện một cuộc gọi đến lĩnh vực bạn chỉ định trong các tập tin cookie, nếu Chrome sẽ không lưu trữ cookie của bạn

    [tùy chọn] Tôi sẽ loại bỏ /api đường dẫn trong lợi của một /


Và rằng nên để các trick.
Hy vọng có được một số trợ giúp

+0

Tôi tin rằng vấn đề là đường dẫn/api và phải là/ –

+1

Khi bạn nói "gửi tên miền khác từ máy chủ cục bộ trong cookie, sử dụng miền của bạn" được lưu trữ "", bạn có nghĩa là máy chủ lưu trữ mặt trước hoặc máy chủ phụ trợ không? – Pathsofdesign

+0

Thông thường nó sẽ là phụ trợ của bạn, nhưng nó thực sự phụ thuộc vào kiến ​​trúc máy chủ của bạn. Bạn có biết WS của bạn ở đâu không? – domokun

7

Bạn cần làm việc trên cả máy chủ và phía máy khách.

Khách hàng

Set $http cấu hình withCredentials để true theo một trong các cách sau:

  1. Theo yêu cầu

    var config = {withCredentials: true}; 
    $http.post(url, config); 
    
  2. Đối với tất cả các yêu cầu

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

server

Đặt tiêu đề phản ứng Access-Control-Allow-Credentials để true.

+1

Không cần phải tạo trình chặn, bây giờ bạn có thể sử dụng '$ httpProvider.defaults.withCredentials = true; ' – vs4vijay

+1

Cảm ơn các mẹo! –

11

Trong bài yêu cầu của bạn về phía khách hàng, hãy chắc chắn để thêm những điều sau đây:

Đối với yêu cầu ajax jquery:

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

Với http dịch vụ $ kiễu góc của:

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

+0

Tôi phát hiện ra trong trường hợp của tôi rằng xhrFields: {...} gây ra một số vấn đề (máy chủ của tôi đáp ứng với một cái gì đó như unknow origin *), vì vậy tôi sử dụng nó thay vì 'beforeSend: function (xhr) { xhr.withCredentials = true; } 'và nó hoạt động tốt – medBo

1

Chỉ cần giải quyết vấn đề như thế này.

Tôi đã làm điều này và không làm việc ...:

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

Cookie được lưu trong trình duyệt, nhưng khi tôi gửi một yêu cầu mới, tất cả các cookie được gửi exept tôi. (Cookie của tôi là JSESSIONID)

sau đó tôi nhìn vào thanh tra chrome và tôi thấy điều này: My session are the JsessionID

vấn đề là không phải là con đường đúng !!!

thì tôi đã thử cách này và cookie của tôi đã được gửi. yay! :

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

Tôi không biết nếu đây là trường hợp của bạn, nhưng điều này làm việc cho tôi.

liên quan!

+0

Greate, giải quyết vấn đề của tôi. – Jane