2015-01-27 22 views
19

Tôi cần đặt tiêu đề Cấp quyền cho Nguồn sự kiện HTML5. Khi sự kiện máy chủ được gửi dường như bị bỏ qua vì Websockets xuất hiện, tôi không thể tìm thấy bất kỳ tài liệu hữu ích nào. Cách tiếp cận tôi đã tìm thấy là chuyển dữ liệu ủy quyền trong url ... nhưng tôi không thích phương thức này.Tiêu đề ủy quyền HTTP trong EventSource (Sự kiện đã gửi của máy chủ)

Tôi đang sử dụng AngularJS và đặt trình chặn trên httpProvider $, nhưng EventSource không bị chặn bởi AngularJS, vì vậy tôi không thể thêm bất kỳ tiêu đề nào.

+0

Bạn có thể chia sẻ mã mà bạn có cho đến giờ, vui lòng – tim

Trả lời

6

Sự kiệnSource không có API để gửi tiêu đề HTTP đến máy chủ. Tôi đã đấu tranh với vấn đề này quá khi tôi đã xây dựng thời gian thực-chat bằng cách sử dụng SSE.

Tuy nhiên tôi cho rằng cookie sẽ tự động được gửi nếu máy chủ SSE của bạn là cùng một máy chủ với máy chủ xác thực của bạn.

2

cách khác để chuyển mã thông báo xác thực là thông qua URL dưới dạng thông số truy vấn, nhưng bạn nên xem xét bảo mật. Ngoài ra, thêm hỗ trợ ủy quyền thông qua truy vấn param ở phía máy chủ.

+0

SSL/TLS có thể được sử dụng trong trường hợp đó, để đảm bảo mã thông báo đó an toàn và bảo mật. Nếu không thì IMO ý tưởng này là thực tế nhất. – crollywood

5

polyfill này thêm hỗ trợ Authorization Tiêu đề: https://github.com/Yaffle/EventSource/

Vì vậy, bạn có thể làm:

new EventSource("https://domain/stream", { authorizationHeader: "Bearer ..." }); 
+0

Bạn có thể vui lòng cung cấp một đoạn của góc làm việc với điều này? Tôi không đạt được nó: l –

+1

Vùng chèn này không hỗ trợ tiêu đề do người dùng xác định. Bạn có muốn liên kết đến một ngã ba có lẽ? – AlexG

+0

Nó đã không phải là một polyfill vì EventSource gốc không hỗ trợ tiêu đề do người dùng xác định, do đó bạn chỉ cần nhận được lỗi/lỗi ẩn khi mã của bạn sẽ sử dụng EventSource gốc. – maksimr

3

Tôi nhận ra bài viết của bạn đã kết thúc một năm trước đây, nhưng tôi tìm thấy bản thân mình trong cùng một thuyền với câu trả lời bây giờ tốt . Tôi hy vọng điều này có thể giúp một ai đó, hoặc ít nhất cung cấp cho họ một số ý tưởng ...

Cookie dường như đủ dễ dàng, nhưng điều gì sẽ xảy ra nếu ai đó chặn cookie? Tôi sẽ phải nhắc họ bật cookie để sử dụng trang web. Tại thời điểm đó, họ bắt đầu tự hỏi liệu họ có thể tin tưởng trang web vì họ đã tắt cookie vì 'lý do bảo mật' hay không. Trong khi đó, tôi muốn cookie được kích hoạt vì lý do bảo mật!

Sử dụng AJAX, người ta có thể dễ dàng POST dữ liệu xác thực qua SSL, nhưng điều đó không thể thực hiện được với SSE. Tôi đã nhìn thấy nhiều bài viết mà mọi người sau đó nói, "chỉ cần sử dụng chuỗi truy vấn", nhưng tôi không muốn xâm phạm bảo mật của khách hàng bằng cách gửi dữ liệu xác thực trong văn bản thuần túy (example.com/stream?sessionID=idvalue) mà ai đó có thể snoop.

Sau khi ngừng bộ não của tôi trong một vài giờ, tôi nhận ra rằng tôi CÓ THỂ hoàn thành mục tiêu tổng thể mà không ảnh hưởng đến dữ liệu auth của khách hàng. Chỉ cần làm rõ, tôi đã không phát hiện ra một số cách để POST khi thiết lập một kết nối EventSource, nhưng nó cho phép trình duyệt an toàn vượt qua một thẻ xác thực với EventSource mỗi khi nó kết nối lại. Chìa khóa là lấy sessionID/token mong muốn vào lastEventID.

Người dùng có thể xác thực như bình thường với tên người dùng/mật khẩu (hoặc bằng AJAX POSTing mã thông báo bạn giữ trong localstorage). Quá trình xác thực AJAX sẽ trả về một đối tượng JSON với một mã thông báo ngắn (hết hạn sau 60 giây hoặc khi được sử dụng) sẽ được lưu trong phần phụ trợ mong muốn của bạn (ví dụ: mySQL) cùng với mã thông báo dài hơn. Tại thời điểm này bạn bắt đầu kết nối SSE của bạn như:

qString = "?slt=" + "value-that-expires-within-seconds"; 
    streamURL = "http://example.com/stream.php"; 
    var streamSource = new EventSource(streamURL + qString); 

    streamSource.addEventListener('auth',function(e) { 
     var authStatus = JSON.parse(e.data); 
     if (authStatus.session !== 'valid') { 
      qString = ""; 
      streamSource.close(); 
     } 
    }) 

Trong PHP tương ứng bạn sẽ làm một cái gì đó như thế này:

 header("Content-Type: text/event-stream\n"); 
     ob_end_flush(); 
     ob_start(); 

     if (isThisShortLivedTokenValid($_GET["slt"])) { 
      // The short-lived-token is still valid... so we will lookup 
      // the value of the corresponding longer-lasting token and 
      // IMMEDIATELY invalidate the short-lived-token in the db. 
      sendMsg($realToken,'auth','session','valid'); 
      exit; 
     } else if (isThisRealTokenValid($_SERVER["HTTP_LAST_EVENT_ID"])){ 
      while (1) { 
       // normal code goes here 
       // if ($someCondition == 'newDataAvailable') sendMsg($realToken,'chat','msg-id','msg-content'); 
      } 
     } else { 
      http_response_code(404); // stop the browser from reconnecting. 
      exit; //quit the PHP script and don't send anything. 
     } 


     function sendMsg($id, $event, $key, $val) { 
      echo "{" . PHP_EOL; 
      echo "event: " . $event . PHP_EOL; 
      echo "id: $id" . PHP_EOL; 
      echo 'data: {"' . $key . '" : "' . $val . '"}' . PHP_EOL; 
      echo "}" . PHP_EOL; 
      echo PHP_EOL; 
      ob_flush(); 
      flush(); 
     } 

     function isThisShortLivedTokenValid($sltValue) { 
      //stuff to connect to DB and determine if the 
      //value is still valid for authentication 
      return $dbResult == $sltValue ? TRUE : FALSE; 
     } 

SSE kết nối với ngắn ngủi-token, PHP xác nhận chống lại ngắn -lived-token và xóa nó khỏi DB vì vậy nó sẽ không bao giờ có thể AUTH một lần nữa. Điều này có phần tương tự khi bạn nhận được tin nhắn mã 6 chữ số để đăng nhập vào ngân hàng trực tuyến.Chúng tôi sử dụng PHP để đẩy mã thông báo REAL (hết hạn sau này) mà chúng tôi đã truy xuất từ ​​cơ sở dữ liệu dưới dạng ID sự kiện. Javascript không thực sự cần thiết để thực hiện bất kỳ điều gì với sự kiện này-- máy chủ sẽ tự động kết thúc kết nối nhưng bạn có thể nghe sự kiện nếu bạn muốn làm nhiều hơn với sự kiện đó.

Tại thời điểm này, kết nối SSE đã kết thúc kể từ khi PHP hoàn thành tập lệnh. Tuy nhiên, trình duyệt sẽ tự động thiết lập lại kết nối (thường là 3 giây). Lần này, nó sẽ gửi lastEventId ... mà chúng ta đặt thành giá trị token trước khi chúng ta bỏ kết nối. Trên kết nối tiếp theo, giá trị này sẽ được sử dụng làm mã thông báo của chúng tôi và ứng dụng sẽ chạy như mong đợi. Nó không thực sự cần thiết để thả các kết nối miễn là bạn bắt đầu sử dụng mã thông báo thực sự là sự kiện-ID khi bạn gửi tin nhắn/sự kiện. Giá trị mã thông báo này được truyền hoàn toàn được mã hóa qua SSL cả khi trình duyệt nhận được nó và trong mọi kết nối tiếp theo đến máy chủ. Giá trị đã được truyền 'trong xóa' đã hết hạn trong vài giây kể từ khi chúng tôi nhận được & đã sử dụng giá trị đó và không còn ai có thể sử dụng giá trị đó nữa. Nếu ai đó cố gắng sử dụng, họ sẽ nhận được 404 RESPONSE.

Nếu bạn đã sử dụng sự kiện dòng ID cho một số mục đích nào khác, điều này có thể không hoạt động 'ra khỏi hộp' trừ khi bạn nối các auth-token và giá trị sử dụng trước đó, và chia nó thành các biến vì vậy trong suốt đối với phần còn lại của ứng dụng. Một cái gì đó như:

// when sending data, send both values 
    $sseID = $token_value . "_" . $previouslyUsedID; 
    sendMsg($sseID,'chat','msg-id','msg-content'); 

    // when a new connection is established, break apart the values 
    $manyIDs = explode("_", $_SERVER["HTTP_LAST_EVENT_ID"]) 
    $token_value = $manyIDs[0] 
    $previouslyUsedID = $manyIDs[1] 
1

Nếu bạn sử dụng ngã ba này của polyfill kiện nguồn bạn sẽ có thể thêm tiêu đề uỷ quyền tương tự như cách các rafaelzlisboa mô tả: https://github.com/AlexGalays/EventSource#923b9a0998fcfd7753040e09aa83764b3cc0230d

Tôi không biết nếu bạn có thể cung cấp các tiêu đề xác thực như một đối số thứ hai như trong ví dụ rafaelzlisboa, tôi đã nhận nó để làm việc bằng cách tạo ra một đối tượng tiêu đề, và đưa tiêu đề uỷ quyền của tôi trong đó, như thế này:

new EventSource("https://domain/stream", { headers: { Authorization: Bearer.... }});

Các vấn đề liên quan