2015-02-23 56 views
10

我已經構建了一個API來爲登錄的用戶生成身份驗證令牌。此時我還有一個用Node.JS編寫的客戶端應用程序。
當我使用用戶證書從客戶端應用程序向API發出請求時,我獲得身份驗證令牌:我應該如何將其存儲在客戶端應用程序中?我不應該在每次想要提供API請求時都要求提供令牌,對嗎?
我想過把令牌放在Cookie中,但我不認爲這是最好的解決方案。 你會推薦什麼?我應該如何存儲由RESTful API生成的令牌?

+0

是您的客戶端應用程序,它是一個node.js服務器,使用任何數據存儲? – 2015-02-23 13:36:35

+0

我使用的是MongoDB – IgorSousaPT 2015-02-23 13:38:09

+0

,您可以像redis一樣製作內存數據存儲以存儲令牌並將其用於進一步請求。使用會話存儲和connect-redis是一個可行的解決方案。 – 2015-02-23 13:48:56

回答

5

成功登錄後,一個唯一的一次性令牌應該創建在服務器端,並存儲在數據庫中,並與用戶ID和時間戳相對應。您將令牌存儲在Cookie客戶端。然後您將令牌傳遞給每個後續的API調用。然後服務器應該檢查令牌是否有效(即未過期,比如發出或更新少於30分鐘前)。如果它是有效的,您可以檢索針對該標記存儲的用戶詳細信息,並執行您需要的任何後端功能(如用戶的身份驗證)。然後,您更新該令牌的時間戳(刷新會話,因爲您希望登錄在超過30分鐘沒有用戶交互後超時)。如果您獲取API調用時令牌已過期或不存在,請重定向至登錄頁面。

此外,您可能已經知道這一點,但要確保令牌是唯一且不可猜測的,我傾向於生成新的隨機GUID並加密它們,請勿使用sequentail ID或類似的東西。

+0

是的,我知道這個獨特和不可猜測的部分,不過謝謝你指出它。我關於cookies方法的問題是,它安全嗎?難道不可能竊取cookie值並訪問其他用戶的私人信息嗎? – IgorSousaPT 2015-02-23 14:06:17

+0

假設您使用的是SSL,那麼使用中間人攻擊難以理解價值。使用唯一的過期令牌會在使用後使令牌無效,所以相對安全。假設用戶在會話期間保持相同的IP(可能),您也可以使用ip驗證該令牌。 但是,有可能是客戶端上的所有cookie信息上傳至第三方網站的惡意代碼,但如果正確實施,我認爲使用cookie對於大多數Web應用程序來說已足夠安全。或者,你可以看看OAuth,這是另一個頭痛的問題,但是廣泛使用的auth方法。 – 2015-02-23 14:25:19

+0

實際上,我使用OAuth2.0來驗證憑據並生成令牌。但是我仍然需要將令牌存儲在客戶端。除非,我得到這個非常錯誤! – IgorSousaPT 2015-02-23 15:04:41

1

我認爲這個鏈接可以幫助你:

事實上,你應該有一個截止日期的標記,所以在發送請求之前,您不必每次都獲取新令牌。當令牌過期時,您只需從服務「刷新令牌」中獲取新的令牌。

關於如何將令牌存儲在客戶端應用程序中的問題,我認爲您可以將其保存在內存(地圖或嵌入式數據庫)中。

否則結束,我不認爲在這種用例中使用cookie是一個好主意。

希望它能幫助你。 Thierry

1

我們正在研究一個使用非常類似方法的應用程序。客戶端應用程序是一個靜態HTML5/JS單頁面應用程序(不需要任何服務器端生成)並與API服務器進行通信。

最好的方法是將會話令牌存儲在內存中:也就是說,在JS代碼中的一個變量內。如果您的客戶端應用程序是單個頁面,那不應該是個問題。
除此之外,我們還將會話令牌保留在sessionStorage中以便在用戶刷新頁面時保留它。爲了在創建新選項卡時保留標記(sessionStorage特定於瀏覽器窗口),我們還在關閉頁面時將其存儲在localStorage中,並將其與打開標籤的計數器一起存儲(當應用程序的所有選項卡都關閉時,我們刪除令牌。

// Handle page reloads using sessionStorage 
var sess = sessionStorage.getItem('session-token') 
if(sess && sess !== 'null') { // Sometimes empty values are a string "null" 
    localStorage.setItem('session-token', sess) 
} 

// Set a counter to check when all pages/tabs of the application are closed 
var counter = parseInt(localStorage.getItem('session-counter') || 0, 10) 
counter++ 
localStorage.setItem('session-counter', counter) 

// Event fired when the page/tab is closing 
window.onbeforeunload = function() { 
    var counter = parseInt(localStorage.getItem('session-counter') || 0, 10) 
    counter-- 
    localStorage.setItem('session-counter', counter) 

    // All pages are closed: remove the session token 
    if(counter <= 0) { 
     // Handle page reloads using sessionStorage 
     sessionStorage.setItem('session-token', localStorage.getItem('session-token')) 

     localStorage.removeItem('session-token') 
    } 
} 

有關的localStorage和sessionStorage的更多信息:https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API

爲什麼不餅乾? Cookie不好,原因有兩個: 1.它們通常更持久,可在瀏覽器窗口和選項卡之間共享,即使在瀏覽器關閉後也可以保留。 2.然而,最重要的是,根據HTTP規範,每次發出請求時都必須將它們發送到Web服務器。如果您設計的應用程序的客戶端與API服務器完全分離,您不希望客戶端的服務器在任何情況下都看到(或登錄)會話令牌。

一些額外的建議:

  1. 會話令牌必須到期。您可以通過將會話令牌存儲在服務器上的數據庫中並在每個請求上驗證它們和/或「簽名」它們(以純文本向令牌添加時間戳,然後添加簽名部分(例如HMAC散列)與您只知道祕密密鑰編碼的時間戳)。
  2. 令牌可以在其生命中多次重複使用。但是,經過一定的秒數後,您可能希望服務器刷新令牌,使舊令牌失效並向客戶端發送新令牌。
相關問題