Token登陸認證

參考文章:html

Token 認證的前因後果前端

先後端分離使用 Token 登陸解決方案web

理解Cookie和Session機制後端

基於 Cookie/Session 的認證方案

Cookie跨域

  • Cookie的工做原理

因爲HTTP是一種無狀態的協議,服務器單從網絡鏈接上無從知道客戶身份。怎麼辦呢?就給客戶端們頒發一個通行證吧,每人一個,不管誰訪問都必須攜帶本身通行證。這樣服務器就能從通行證上確認客戶身份了。這就是。 cookie指的就是瀏覽器裏面能永久存儲的一種數據,僅僅是瀏覽器實現的一種數據存儲功能。瀏覽器

Cookie其實是一小段的文本信息。客戶端請求服務器,若是服務器須要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器。服務器檢查該Cookie,以此來辨認用戶狀態。服務器還能夠根據須要修改Cookie的內容。安全

注意Cookie功能須要瀏覽器的支持。若是瀏覽器不支持Cookie(如大部分手機中的瀏覽器)或者把Cookie禁用了,Cookie功能就會失效。不一樣的瀏覽器採用不一樣的方式保存CookieIE瀏覽器會以文本文件形式保存,一個文本文件保存一個Cookiebash

  • Cookie的不可跨域名性

Cookie具備不可跨域名性。根據Cookie規範,瀏覽器訪問Google只會攜帶GoogleCookie,而不會攜帶BaiduCookie。瀏覽器判斷一個網站是否能操做另外一個網站Cookie的依據是域名。服務器

Sessioncookie

Session是另外一種記錄客戶狀態的機制,不一樣的是Cookie保存在客戶端瀏覽器中,而Session保存在服務器上。客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上。這就是Session。客戶端瀏覽器再次訪問時只須要從該Session中查找該客戶的狀態就能夠了。

若是說Cookie機制是經過檢查客戶身上的「通行證」來肯定客戶身份的話,那麼Session機制就是經過檢查服務器上的「客戶明細表」來確認客戶身份。

session 也是相似的道理,服務器要知道當前發請求給本身的是誰。爲了作這種區分,服務器就要給每一個客戶端分配不一樣的「身份標識」,而後客戶端每次向服務器發請求的時候,都帶上這個「身份標識」,服務器就知道這個請求來自於誰了。對於瀏覽器客戶端,你們都默認採用 cookie 的方式,保存這個「身份標識」。

服務器使用session把用戶的信息臨時保存在了服務器上,用戶離開網站後session會被銷燬。這種用戶信息存儲方式相對cookie來講更安。

但是session有一個缺陷:若是web服務器作了負載均衡,那麼下一個操做請求到了另外一臺服務器的時候session會丟失。

提示Session的使用比Cookie方便,可是過多的Session存儲在服務器內存中,會對服務器形成壓力。

Cookie與Session的區別和聯繫

  1. cookie數據存放在客戶的瀏覽器上,session數據放在服務器上;

  2. cookie不是很安全,別人能夠分析存放在本地的COOKIE並進行COOKIE欺騙,考慮到安全應當使用session

  3. session會在必定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能。考慮到減輕服務器性能方面,應當使用COOKIE

  4. 單個cookie在客戶端的限制是3K,就是說一個站點在客戶端存放的COOKIE不能超過3K;

CookieSession的方案雖然分別屬於客戶端和服務端,可是服務端的session的實現對客戶端的cookie有依賴關係的,上面我講到服務端執行session機制時候會生成session的id值,這個id值會發送給客戶端,客戶端每次請求都會把這個id值放到http請求的頭部發送給服務端,而這個id值在客戶端會保存下來,保存的容器就是cookie,所以當咱們徹底禁掉瀏覽器的cookie的時候,服務端的session也會不能正常使用。

基於token的認證方式

在大多數使用Web API的互聯網公司中,tokens 是多用戶下處理認證的最佳方式。

如下幾點特性會讓你在程序中使用基於Token的身份驗證

1.無狀態、可擴展

2.支持移動設備

3.跨程序調用

4.安全

Token的起源

在介紹基於Token的身份驗證的原理與優點以前,不妨先看看以前的認證都是怎麼作的。

  • 基於服務器的驗證

咱們都是知道HTTP協議是無狀態的,這種無狀態意味着程序須要驗證每一次請求,從而辨別客戶端的身份。

在這以前,程序都是經過在服務端存儲的登陸信息來辨別請求的。這種方式通常都是經過存儲Session來完成。

  • 基於服務器驗證方式暴露的一些問題

1.Seesion:每次認證用戶發起請求時,服務器須要去建立一個記錄來存儲信息。當愈來愈多的用戶發請求時,內存的開銷也會不斷增長。

2.可擴展性:在服務端的內存中使用Seesion存儲登陸信息,伴隨而來的是可擴展性問題。

3.CORS(跨域資源共享):當咱們須要讓數據跨多臺移動設備上使用時,跨域資源的共享會是一個讓人頭疼的問題。在使用Ajax抓取另外一個域的資源,就能夠會出現禁止請求的狀況。

4.CSRF(跨站請求僞造):用戶在訪問銀行網站時,他們很容易受到跨站請求僞造的攻擊,而且可以被利用其訪問其餘的網站。

在這些問題中,可擴展行是最突出的。所以咱們有必要去尋求一種更有行之有效的方法。

基於Token的驗證原理

基於Token的身份驗證是無狀態的,咱們不將用戶信息存在服務器中。這種概念解決了在服務端存儲信息時的許多問題。NoSession意味着你的程序能夠根據須要去增減機器,而不用去擔憂用戶是否登陸。

基於Token的身份驗證的過程以下:

1.用戶經過用戶名和密碼發送請求。

2.服務器端程序驗證。

3.服務器端程序返回一個帶簽名token 給客戶端。

4.客戶端儲存token,而且每次訪問API都攜帶Token到服務器端的。

5.服務端驗證token,校驗成功則返回請求數據,校驗失敗則返回錯誤碼。

Tokens的優點

  • 無狀態、可擴展

在客戶端存儲的Tokens是無狀態的,而且可以被擴展。基於這種無狀態和不存儲Session信息,負載負載均衡器可以將用戶信息從一個服務傳到其餘服務器上。 tokens本身hold住了用戶的驗證信息。

  • 安全性

請求中發送token而再也不是發送cookie可以防止CSRF(跨站請求僞造)。即便在客戶端使用cookie存儲tokencookie也僅僅是一個存儲機制而不是用於認證。不將信息存儲在Session中,讓咱們少了對session操做。

token是有時效的,一段時間以後用戶須要從新驗證。

  • 可擴展性

Tokens可以建立與其它程序共享權限的程序。

  • 多平臺跨域

咱們提早先來談論一下CORS(跨域資源共享),對應用程序和服務進行擴展的時候,須要介入各類各類的設備和應用程序。

須要設置有效期嗎?

對於這個問題,咱們不妨先看兩個例子。一個例子是登陸密碼,通常要求按期改變密碼,以防止泄漏,因此密碼是有有效期的;另外一個例子是安全證書。SSL 安全證書都有有效期,目的是爲了解決吊銷的問題。因此不管是從安全的角度考慮,仍是從吊銷的角度考慮,Token 都須要設有效期。

  • 那麼有效期多長合適呢?

只能說,根據系統的安全須要,儘量的短,但也不能短得離譜

  • 而後新問題產生了,若是用戶在正常操做的過程當中,Token 過時失效了,要求用戶從新登陸……用戶體驗豈不是很糟糕?

一種方案,使用 Refresh Token,它能夠避免頻繁的讀寫操做。這種方案中,服務端不須要刷新 Token 的過時時間,一旦 Token 過時,就反饋給前端,前端使用 Refresh Token 申請一個全新Token 繼續使用。這種方案中,服務端只須要在客戶端請求更新 Token 的時候對 Refresh Token 的有效性進行一次檢查,大大減小了更新有效期的操做,也就避免了頻繁讀寫。固然 Refresh Token 也是有有效期的,可是這個有效期就能夠長一點了,好比,以天爲單位的時間。

  • 時序圖表示

使用 TokenRefresh Token 的時序圖以下:

1)登陸

2)業務請求

3) Token過時,刷新 Token

上面的時序圖中並未提到 Refresh Token 過時怎麼辦。不過很顯然, Refresh Token 既然已通過期,就該要求用戶從新登陸了。

項目中使用token總結

使用基於 Token 的身份驗證方法,在服務端不須要存儲用戶的登陸記錄。大概的流程是這樣的:

1.前端使用用戶名跟密碼請求首次登陸

2.後服務端收到請求,去驗證用戶名與密碼是否正確

3.驗證成功後,服務端會根據用戶id、用戶名、定義好的祕鑰、過時時間生成一個 Token,再把這個 Token 發送給前端

4.前端收到 返回的Token ,把它存儲起來,好比放在 Cookie 裏或者 Local Storage

export interface User {
    token: string;
    userInfo: UserInfo | any;
    companyInfo: CompanyInfo | any;
    resources?: string[];
}
複製代碼
save(key: string, value: any, storageType ?: StorageType) {
    return this.storageService.put(
        {
            pool: key,
            key: 'chris-app',
            storageType: StorageType.localStorage
        },
        value
    );
}
this.storageService.save(CACHE_USER_KEY, user);
複製代碼

5.前端每次路由跳轉,判斷 localStroage 有無 token ,沒有則跳轉到登陸頁。有則請求獲取用戶信息,改變登陸狀態; 6.前端每次向服務端請求資源的時候須要在請求頭裏攜帶服務端簽發的Token

HttpInterceptor => headers = headers.set('token', this.authService.getToken());
複製代碼

7.服務端收到請求,而後去驗證前端請求裏面帶着的 Token。沒有或者 token 過時,返回401。若是驗證成功,就向前端返回請求的數據。

8.前端獲得 401 狀態碼,重定向到登陸頁面。

HttpInterceptor => 
    401: '用戶登錄狀態失效,請從新登錄。'
複製代碼
相關文章
相關標籤/搜索