當前位置:首頁 » 網頁前端 » 前端請求token驗證
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

前端請求token驗證

發布時間: 2023-01-13 12:07:21

1. JWT生成token及過期處理方案

## 業務場景

在前後分離場景下,越來越多的項目使用token作為介面的安全機制,APP端或者WEB端(使用VUE、REACTJS等構建)使用token與後端介面交互,以達到安全的目的。本文結合stackoverflow以及本身項目實踐,試圖總結出一個通用的,可落地的方案。

## 基本思路

- 單個token

1. token(A)過期設置為15分鍾

2. 前端發起請求,後端驗證token(A)是否過期;如果過期,前端發起刷新token請求,後端設置已再次授權標記為true,請求成功

3. 前端發起請求,後端驗證再次授權標記,如果已經再次授權,則拒絕刷新token的請求,請求成功

4. 如果前端每隔72小時,必須重新登錄,後端檢查用戶最後一次登錄日期,如超過72小時,則拒絕刷新token的請求,請求失敗

- 授權token加上刷新token

用戶僅登錄一次,用戶改變密碼,則廢除token,重新登錄

## 1.0實現

1.登錄成功,返回access\_token和refresh\_token,客戶端緩存此兩種token; 

2.使用access_token請求介面資源,成功則調用成功;如果token超時,客戶端 

攜帶refresh\_token調用中間件介面獲取新的access\_token; 

3.中間件接受刷新token的請求後,檢查refresh_token是否過期。 

如過期,拒絕刷新,客戶端收到該狀態後,跳轉到登錄頁; 

如未過期,生成新的access\_token和refresh\_token並返回給客戶端(如有可能,讓舊的refresh\_token失效),客戶端攜帶新的access\_token重新調用上面的資源介面。 

4.客戶端退出登錄或修改密碼後,調用中間件注銷舊的token(使access\_token和refresh\_token失效),同時清空客戶端的access\_token和refresh\_toke。

後端表 

id user\_id client\_id client\_secret refresh\_token expire\_in create\_date del_flag

## 2.0實現

場景: access\_token訪問資源 refresh\_token授權訪問 設置固定時間X必須重新登錄

1.登錄成功,後台jwt生成access\_token(jwt有效期30分鍾)和refresh\_token(jwt有效期15天),並緩存到redis(hash-key為token,sub-key為手機號,value為設備唯一編號(根據手機號碼,可以人工廢除全部token,也可以根據sub-key,廢除部分設備的token。),設置過期時間為1個月,保證最終所有token都能刪除),返回後,客戶端緩存此兩種token; 

2.使用access\_token請求介面資源,校驗成功且redis中存在該access\_token(未廢除)則調用成功;如果token超時,中間件刪除access\_token(廢除);客戶端再次攜帶refresh\_token調用中間件介面獲取新的access_token; 

3.中間件接受刷新token的請求後,檢查refresh_token是否過期。 

如過期,拒絕刷新,刪除refresh_token(廢除); 客戶端收到該狀態後,跳轉到登錄頁; 

如未過期,檢查緩存中是否有refresh\_token(是否被廢除),如果有,則生成新的access\_token並返回給客戶端,客戶端接著攜帶新的access_token重新調用上面的資源介面。 

4.客戶端退出登錄或修改密碼後,調用中間件注銷舊的token(中間件刪除access\_token和refresh\_token(廢除)),同時清空客戶端側的access\_token和refresh\_toke。 

5.如手機丟失,可以根據手機號人工廢除指定用戶設備關聯的token。 

6.以上3刷新access_token可以增加根據登錄時間判斷最長X時間必須重新登錄,此時則拒絕刷新token。(拒絕的場景:失效,長時間未登錄,頻繁刷新)

2.0 變動 

1.登錄 

2.登錄攔截器 

3.增加刷新access_token介面 

4.退出登錄 

5.修改密碼

## 3.0實現

場景:自動續期 長時間未使用需重新登錄

1.登錄成功,後台jwt生成access\_token(jwt有效期30分鍾),並緩存到redis(hash-key為access\_token,sub-key為手機號,value為設備唯一編號(根據手機號碼,可以人工廢除全部token),設置access_token過期時間為7天,保證最終所有token都能刪除),返回後,客戶端緩存此token;

2.使用access\_token請求介面資源,校驗成功且redis中存在該access\_token(未廢除)則調用成功;如果token超時,中間件刪除access\_token(廢除),同時生成新的access\_token並返回。客戶端收到新的access_token, 

再次請求介面資源。

3.客戶端退出登錄或修改密碼後,調用中間件注銷舊的token(中間件刪除access\_token(廢除)),同時清空客戶端側的access\_token。

4.以上2 可以增加根據登錄時間判斷最長X時間必須重新登錄,此時則拒絕刷新token。(拒絕的場景:長時間未登錄,頻繁刷新)

5.如手機丟失,可以根據手機號人工廢除指定用戶設備關聯的token。

3.0 變動

1.登錄 

2.登錄攔截器 

3.退出登錄 

4.修改密碼

1.3 場景:token過期重新登錄 長時間未使用需重新登錄

1.登錄成功,後台jwt生成access\_token(jwt有效期7天),並緩存到redis,key為 "user\_id:access\_token",value為access\_token(根據用戶id,可以人工廢除指定用戶全部token),設置緩存過期時間為7天,保證最終所有token都能刪除,請求返回後,客戶端緩存此access_token;

2.使用access\_token請求介面資源,校驗成功且redis中存在該access\_token(未廢除)則調用成功;如果token超時,中間件刪除access\_token(廢除),同時生成新的access\_token並返回。客戶端收到新的access_token, 

再次請求介面資源。

3.客戶端退出登錄或修改密碼後,調用中間件注銷舊的token(中間件刪除access\_token(廢除)),同時清空客戶端側的access\_token。

4.以上2 可以增加根據登錄時間判斷最長X時間必須重新登錄,此時則拒絕刷新token。(拒絕的場景:長時間未登錄,頻繁刷新)

5.如手機丟失,可以根據手機號人工廢除指定用戶設備關聯的token。

1.3 變動

1.登錄 

2.登錄攔截器 

3.退出登錄 

4.修改密碼

# 解決方案

2.0 場景: access\_token訪問資源 refresh\_token授權訪問 設置固定時間X必須重新登錄

1.登錄成功,後台jwt生成access\_token(jwt有效期30分鍾)和refresh\_token(jwt有效期15天),並緩

存到redis(hash-key為token,sub-key為手機號,value為設備唯一編號(根據手機號碼,可以人工廢除全

部token,也可以根據sub-key,廢除部分設備的token。),設置過期時間為1個月,保證最終所有token都

能刪除),返回後,客戶端緩存此兩種token;

2.使用access\_token請求介面資源,校驗成功且redis中存在該access\_token(未廢除)則調用成功;如果

token超時,中間件刪除access\_token(廢除);客戶端再次攜帶refresh\_token調用中間件介面獲取新的

access_token;

3.中間件接受刷新token的請求後,檢查refresh_token是否過期。

如過期,拒絕刷新,刪除refresh_token(廢除); 客戶端收到該狀態後,跳轉到登錄頁;

如未過期,檢查緩存中是否有refresh\_token(是否被廢除),如果有,則生成新的access\_token並返回給

客戶端,客戶端接著攜帶新的access_token重新調用上面的資源介面。

4.客戶端退出登錄或修改密碼後,調用中間件注銷舊的token(中間件刪除access\_token和refresh\_token(

廢除)),同時清空客戶端側的access\_token和refresh\_toke。

5.如手機丟失,可以根據手機號人工廢除指定用戶設備關聯的token。

6.以上3刷新access_token可以增加根據登錄時間判斷最長X時間必須重新登錄,此時則拒絕刷新token。(

拒絕的場景:失效,長時間未登錄,頻繁刷新)

2.0 變動

1.登錄

2.登錄攔截器

3.增加刷新access_token介面

4.退出登錄

5.修改密碼

3.0 場景:自動續期 長時間未使用需重新登錄

1.登錄成功,後台jwt生成access_token(jwt有效期30分鍾),並緩存到redis(hash-key為

access_token,sub-key為手機號,value為設備唯一編號(根據手機號碼,可以人工廢除全部token,也可以

根據sub-key,廢除部分設備的token。),設置access_token過期時間為1個月,保證最終所有token都能刪

除),返回後,客戶端緩存此token;

2.使用access\_token請求介面資源,校驗成功且redis中存在該access\_token(未廢除)則調用成功;如果

token超時,中間件刪除access\_token(廢除),同時生成新的access\_token並返回。客戶端收到新的

access_token,

再次請求介面資源。

3.客戶端退出登錄或修改密碼後,調用中間件注銷舊的token(中間件刪除access_token(廢除)),同時清

空客戶端側的access_token。

4.以上2 可以增加根據登錄時間判斷最長X時間必須重新登錄,此時則拒絕刷新token。(拒絕的場景:長

時間未登錄,頻繁刷新)

5.如手機丟失,可以根據手機號人工廢除指定用戶設備關聯的token。

3.0 變動

1.登錄

2.登錄攔截器

3.退出登錄

4.修改密碼

4.0 場景:token過期重新登錄 長時間未使用需重新登錄

1.登錄成功,後台jwt生成access_token(jwt有效期7天),並緩存到redis,key為

"user\_id:access\_token" + 用戶id,value為access_token(根據用戶id,可以人工廢除指定用戶全部

token),設置緩存過期時間為7天,保證最終所有token都能刪除,請求返回後,客戶端緩存此

access_token;

2.使用access\_token請求介面資源,校驗成功且redis中存在該access\_token(未廢除)則調用成功;如果

token超時,中間件刪除access\_token(廢除),同時生成新的access\_token並返回。客戶端收到新的

access_token,

再次請求介面資源。

3.客戶端退出登錄或修改密碼後,調用中間件注銷舊的token(中間件刪除access_token(廢除)),同時清

空客戶端側的access_token。

4.以上2 可以增加根據登錄時間判斷最長X時間必須重新登錄,此時則拒絕刷新token。(拒絕的場景:長

時間未登錄,頻繁刷新)

5.如手機丟失,可以根據手機號人工廢除指定用戶設備關聯的token。

4.0 變動

1.登錄

2.登錄攔截器

3.退出登錄

4.修改密碼

## 最終實現

### 後端

1. 在登錄介面中 如果校驗賬號密碼成功 則根據用戶id和用戶類型創建jwt token(有效期設置為-1,即永不過期),得到A

2. 更新登錄日期(當前時間new Date()即可)(業務上可選),得到B

3. 在redis中緩存key為ACCESS_TOKEN:userId:A(加上A是為了防止用戶多個客戶端登錄 造成token覆蓋),value為B的毫秒數(轉換成字元串類型),過期時間為7天(7 * 24 * 60 * 60)

4. 在登錄結果中返回json格式為{"result":"success","token": A}

5. 用戶在介面請求header中攜帶token進行登錄,後端在所有介面前置攔截器進行攔截,作用是解析token 拿到userId和用戶類型(用戶調用業務介面只需要傳token即可),

如果解析失敗(拋出SignatureException),則返回json(code = 0 ,info= Token驗證不通過, errorCode = '1001');

此外如果解析成功,驗證redis中key為ACCESS_TOKEN:userId:A 是否存在 如果不存在 則返回json(code = 0 ,info= 會話過期請重新登錄, errorCode = '1002');

如果緩存key存在,則自動續7天超時時間(value不變),實現頻繁登錄用戶免登陸。

6. 把userId和用戶類型放入request參數中 介面方法中可以直接拿到登錄用戶信息

7. 如果是修改密碼或退出登錄 則廢除access_tokens(刪除key)

### 前端(VUE)

1. 用戶登錄成功,則把username存入cookie中,key為loginUser;把token存入cookie中,key為accessToken

  把token存入Vuex全局狀態中

2. 進入首頁

2. 前端的token驗證 (以vue為例)

1、第一次登錄的時候,前端調後端的登陸介面,發送用戶名和密碼

2、後端收到請求,驗證用戶名和密碼,驗證成功,就給前端返回一個token

3、前端拿到token,將token存儲到localStorage和vuex中,並跳轉路由頁面

4、前端每次跳轉路由,就判斷 localStroage 中有無 token ,沒有就跳轉到登錄頁面,有則跳轉到對應路由頁面

5、每次調後端介面,都要在請求頭中加token

6、後端判斷請求頭中有無token,有token,就拿到token並驗證token,驗證成功就返回數據,驗證失敗(例如:token過期)就返回401,請求頭中沒有token也返回401

7、如果前端拿到狀態碼為401,就清除token信息並跳轉到登錄頁面

3. NodeJS(Express框架)實現 Token 驗證免密登錄 (一)

看文章之前,強烈建議先把項目拉取下來!案例來自小弟的開源項目 「項目Github」

文章內容只是個人學習的一些總結經驗,不具有權威性,這是 Node 服務端的實現,後面會寫前端的實現

常見的 Token 驗證方式種:

推薦閱讀:

JWT 超詳細分析

說一說幾種常用的登錄認證方式,你用的哪種

推薦閱讀:

JSON Web Token 入門教程

JSON Web Token - 在Web應用間安全地傳遞信息

首先我們先安裝 jsonwebtoken 和 express-jwt 這兩個中間件

jsonwebtoken : 用於生成 Token 。它也有解析 Token 的功能

express-jwt : 用於解析 Token(比 jsonwebtoken 解決方便) , 它把解析之後的數據,存放到 requset.user 中

如果你看了上面 JWT 介紹的文章,就知道 JWT 是由三部分組成的,分別是 載荷(Payload) 、 頭部(Header) 、 簽名(Signature) 。

jsonwebtoken 給我們提供了 sign(payload, secretOrPrivateKey, [options, callback]) 方法。sign 方法對應的其實就是 JWT 簽名(Signature) 的動作

payload:荷載 ,參數類型:對象secretOrPrivateKey:自定義的密鑰,密鑰屬於敏感信息。參數類型:字元串options:可以配置 header 、荷載、指定演算法類型。參數類型:對象callback:回調

眼尖的朋友應該發現, payload 和 options 兩個 參數 都可以配置荷,下面有例子。根據自己的習慣選擇就好

Payload 部分 JWT 規定了7個官方欄位,這些欄位都是可選欄位。可直接以對象的形式傳給 payload 參數。

options 中也可以接受以上七個欄位,不過欄位名稱有所區別。

除此之後 options 提供了 algorithm 和 header ,分別對應使用的加密演算法和 JWT 的 Header 部分,其實 algorithm 應該也是屬於 Header 部分的。

說了這么多,其實我們一般常用的只有 exp(expiresIn) 和 algorithm 這兩個欄位,

例子一:

token 的有效時間是配置在 option 里

例子二:

我們也可以在 payload 里配置有效時間

jsonwebtoken 除了生成 token 外,還提供了解析驗證 token 的方法, jwt.verify(token, secretOrPublicKey, [options, callback]) 。

這里就不演示了, 感興趣的朋友可以參考文檔: 「JsonWebToken」

express-jwt 是針對 express 框架開發的 JWT Token 驗證中間件。我先來簡單說以下它的用法。

主要有兩種方式,一種是哪些請求需要驗證就往哪裡加驗證;另外一種是先給全部請求加上驗證,再給不需要驗證的請求配置 白名單 。

方式一:

看完上面的例子,很顯然不符合我們的逾期,一個正常的項目有個幾十個 api 是分分鍾的事。我們不可能一個個給他加上檢驗

方式二:

這種方式是不是方便很多,而且更美觀,維護起來也更方便

Token 解析出來的用戶信息,默認存放在 req.user , 可以直接 req.user.userId 來使用生成 Token 時填進去的用戶id

你也通過 requestProperty 和 resultProperty 來設置用戶信息存放的對象。

這里就不展開,詳細文檔參考: express-jwt

可以使用 app.use() 來注冊處理驗證不通過的情況

到這里 Token 的生成、驗證、檢驗不通過錯誤處理就完成了。 Token 生成一般是在登錄之後生成,並返回給前端,前端拿到 Token ,並在每次請求 api 的時候攜帶上 Token , Token 就相當於這個用戶的身份,不要輕易泄露。

Token一旦簽發,不能主動讓它失效,只能等待它有效期過才能失效。也就是說就算你修改了密碼,之前的 Token 也還是有效的。你可以修改後端生成 Token 時使用的密鑰,不讓之前的 Token 檢驗通過,但是這就表示之前所有生成 Token 都失效了,做不到針對某個用戶進行注銷。這顯然也不合適的。 所以用戶修改密碼時,前端一般都要清除之前保存的 Token,再重獲取新的 Token

有朋友應該會想到在後端把 Token 儲存起來,每一個用戶對應一個 token。修改賬號時,再生成一個新的 Token 覆蓋之前的 Token,但這就違背了使用 Token 的目的,Token 的使用很大程度就為了減少伺服器的壓力。把盡可能多的信息存儲在客戶端而不是服務端。

使用 Token 可以防禦 CSRF 攻擊,之前寫過一篇關於網路安全的文章,感興趣的朋友可以看一下 「XSS 攻擊、CSRF 攻擊、SQL 注入、流量劫持(DNS 劫持、HTTP 劫持)—— 瀏覽器安全」

4. token什麼意思 前端如何使用token

大家好,從網上找了很多關於token的文章,都是提到要生成一個token,然後前端每次請求的時候,要使用這個token,請問下如何在前端使用生成的token?
前端能就使用jQuery搞定,還是需要其他的前端框架配合?能有這方面的完整示例嗎?
做後端的,對前端的東西有些不太懂,請見諒
先謝謝大家了!!

解決方案1:
一般是後端有個結構給你拿token的,然後你請求的時候,根據約定
把token
放在header中
放uri參數中
放body表單里
給後端
解決方案2:
因為http協議是無狀態的 token是後台給你發的一個唯一標識 你再去訪問後台時帶上這個token 後台就知道你是誰了
同session的作用
解決方案3:
前台生成的token,可能會存在安全性問題吧
解決方案4:
你做後台應該很了解token才對呀。
用戶登錄後,生成一個session_id,即token,可以存在redis里。然後前端或客戶端保存起來,存cookie或者LS都行,然後所有的請求作為基類參數帶上(也有通過cookie帶的),然後server端再取到後,驗證你是不是你。
解決方案5:
使用領域很多,以表單為例子:
後台生成token.
前端列印表單,並且講該token變成隱藏項。<input type="hide" value="{{token}}">
客戶提交表單。
後台驗證提交的token合法性。
驗證成功,處理表單。驗證失敗,返回錯誤處理頁面。

解決方案6:
token一般都是後端生成的,在登陸之後返回,前端保存token,之後每次請求都帶上token來驗證身份。
解決方案7:
問題是前端生成的token給後台有用嗎
解決方案8:
一般token都是伺服器端生成,做csrf的。我在補充下我見過前端生成的栗子,雖然沒啥卵用,但讓我廢了好大的勁才發現。
譬如你有一個驗證碼的表單,你在傳遞驗證碼的時候,新增一個隱藏域,將驗證碼用你本地的js加密後,作為參數傳遞,這樣在伺服器端可以檢測驗證碼是不是被篡改過。
但這樣沒啥卵用,因為在提交的時候用同樣的js模擬即可。
解決方案9:
大多數情況下,token作為一種令牌,都是在伺服器端生成,生成的方法很多,從簡單點的對時間或者id或者兩個混合起來進行哈希運算的值到自己設計更復雜的演算法都可以,生成的目的是為了給前端下一次通信時使用這個token作為令牌,當作為一個請求資源的許可的標識,而伺服器則會視這個token在一段時間內都是有效的,並且還可以額外看情況加上是否是同一個ip之類的其它的限制,從而防止某種資源被非法訪問
偶有前端(包括本地客戶端或者app)生成token的情況是已經約定好了一個好的加密機制,伺服器可以信任客戶端的這個輸入的情況下可以由前端或者客戶端生成

5. 鑒權操作流程(前端邏輯)

1.用戶登錄 調取介面 去獲取對應的token,此時將token 存儲在了sessionStorage中。項目的最開始是去獲取當前用戶的token。(base64加密),之後調用token有效時間和校驗token是否失效。
2.公共請求方法 request 函數在請求頭添加 token,即每次的相關請求都帶有了當前用戶的token信息,如果token在有效期內則可以正常請求。否則便會拋出異常。
3.假如token的有效時間是3600s,但是用戶很久沒有操作系統,會啟動用戶鎖定狀態,通過監控用戶的操作時間差來判斷鎖定的狀態。正常情況下token是不會過期的,因為在token的過期前幾分鍾內會進行token的更新操作,理論上token是不會過期的。所以當用戶重新操作系統的時候,超過了一定時間之後需要用戶重新登錄系統來,其實也是調取的token的介面,去獲取新的token,並替換之前的token。(但是這里沒有考慮到的一種情況是如果項目一直在啟動,但是服務重啟了,或者其他原因導致前端的token在驗證的時候不通過,這樣就會導致頁面的鎖定狀態無法打開,這時候前端做的處理是重新跳轉到登錄頁,並刪除token,就像第一次登錄系統一樣。)

6. 服務端如何校驗token的是否正確

服務端第一次返回登錄請求token的時候,服務端是校驗了用戶,並綁定了用戶關系,之後才返回了這個token,也就說,服務端保存了token和登錄用戶賬戶的對應關系,不管之後的token怎麼變,都是伺服器校驗上一次的token,並返回新的token,token和用戶賬戶的對應關系一直在服務端更新並維護,對於客戶端來講,無需判斷token是誰,伺服器下發什麼,就返回什麼,檢驗是服務端處理

7. Token是什麼和session、cookie相比,使用場景有什麼區別

在Web開發領域,相信大家對於Cookie和Session都很熟悉,Cookie和Session都是會話保持技術的解決方案。隨著技術的發展,Token機制出現在我們面前,不過很多開發者對於Token和Cookie、Session的區別及使用場景分辨不清。

Cookie和Session的用途

要知道我們訪問網站都是通過HTTP協議或HTTPS協議來完成的, HTTP協議它本身是無狀態的協議 (即:伺服器無法分辨哪些請求是來源於同個客戶)。而業務層面會涉及到客戶端與伺服器端的交互(同網站下多個頁面間能共享數據),此時伺服器端必須要保持會話狀態,這樣才能進行用戶身份的鑒別。

由於HTTP無狀態的特性,如果要實話客戶端和伺服器端的會話保持,那就需要其它機制來實現,於是Cookie和Session應運而生。

通常情況下, Session和Cookie是搭配在一起使用的 。

Token是什麼

上面說到的Session和Cookie機制來保持會話,會存在一個問題:客戶端瀏覽器只要保存自己的SessionID即可,而 伺服器卻要保存所有用戶的Session信息,這對於伺服器來說開銷較大,而且不利用伺服器的擴展 (比如伺服器集群時,Session如何同步存儲就是個問題)!

於是有人思考,如果把Session信息讓客戶端來保管而且無法偽造不就可以解決這個問題了?進而有了Token機制。

Token俗稱為「令牌」 ,它的構成是:

Token機制下的認證流程

Token機制其實和Cookie機制極其相似 ,主要有以下流程:

1、用戶登錄進行身份認證,認證成功後伺服器端生成Token返回給客戶端;

2、客戶端接收到Token後保存在客戶端(可保存在Cookie、LocalStorage、SessionStorage中);

3、客戶端再次請求伺服器端時,將Token作為請求頭放入Headers中;

4、伺服器端接收請求頭中的Token,將用戶參數按照既定規則再進行一次簽名,兩次簽名若一致則認為成功,反之數據存在篡改請求失敗。


(生成簽名示例圖)

(驗證簽名示例圖)

Token與Cookie+Session的區別

Cookie其實也充當的是令牌作用,但它是「有狀態」的; 而Token令牌是無狀態的,更利於分布式部署。


session和cookie

在講Token之前,先簡單說說什麼是session和cookie。

Token

但是這里會有個問題, 伺服器要保存所有用戶的session信息,開銷會很大,如果在分布式的架構下,就需要考慮session共享的問題,需要做額外的設計和開發 ,例如把session中的信息保存到Redis中進行共享;所以因為這個原因,有人考慮這些信息是否可以讓客戶端保存,可以保存到任何地方,並且保證其安全性,於是就有了Token。

Token是服務端生成的一串字元串,可以看做客戶端進行請求的一個令牌。

基於Token的認證流程

整體的流程是這樣的:

總結 希望我的回答,能夠幫助到你!我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注。

Token顧名思義就是令牌、憑證、鑰匙 。只有這把鑰匙,你才能打開門。token一般都是服務端生成,比如一個web系統,用戶登錄的時候,服務端校驗用戶名密碼通過以後,會生成一個token,同時會生成refreshToken和一個過期時間。然後將refreshToken和token返回給客戶端。客戶端會將token保存下來。後續所有的請求都會攜帶這個token。服務端會判斷當前token是否存在已經是否過期。如果token不存在或者過期就會拒絕本次請求。如果token過期怎麼辦,就用refreshToken刷新時間。當然這里可能還有別的方案。比如只生成token,每次請求的時候都刷新過期時間。如果長時間沒有刷新過期時間,那token就會過期。

session就是回話,這是服務端的一種操作。當你第一次訪問一個web網站的時候,服務端會生成一個session,並有一個sessionid和他對應。這個session是存儲到內存中的,你可以向這個session中寫入信息,比如當前登錄用戶的信息。sessionid會被返回到客戶端,客戶端一般採用cookie來保存。當然這個cookie不用人為寫入。用tomcat容器來舉個例子。 當後端調用HttpServletRequest對象的getSession的方法的時候,tomcat內部會生成一個jsessonid(tomcat sessionid的叫法)。這個jsessonid會隨本次請求返回給客戶端。響應頭信息

這個jessionid就會寫到cookie中。之後jessionid就會通過cookie傳遞到服務端。

這里我們就會很清楚了, session的數據是存儲到內存中。那問題就來了,如果我們的服務是分布式部署,有多台機器的話,可能我們第一次登陸的時候,我們把用戶的信息存儲到了session,但是後面的請求到了B機器上,那B機器是獲取不到用戶的session的。另外就是session存儲在內存中,那伺服器重啟,session就丟失了,這就是他的弊端。現在有一些技術,例如session共享、iphash、session持久等也可以解決上述問題 。

cookie是瀏覽器的一種策略。上述講到了sessionid就是存儲在cookie中的。我們知道http協議是無狀態的,cookie就是用來解決這個問題的。cookie中可以用來保存服務端返回的一些用戶信息的,例如前文提到的token、sessionid。每一次的請求,都會攜帶這些cookie。服務端從請求頭中取到cookie中的信息,就可以識別本次請求的來源,這樣,http是不是就變成有狀態的了。

這里說幾點cookie注意事項。

1、cookie存放在客戶端,所以是不安全的。人為可以清除

2、cookie有過期時間設定。如果不設置過期時間,說明這個cookie就是當前瀏覽器的會話時間,瀏覽器關了,cookie 就存在了。如果有過期時間,cookie就會存儲到硬碟上,瀏覽器關閉不影響cookie。下次打開瀏覽器,cookie還存在

3、cookie有大小的限制,4KB。

這個問題,網上有很多的答案,相信都看過了,估計也沒有看明白。所以我就不去網上復制了,用自己的話,盡量說通俗,說重點。

cookie和session實際上是同一套認證流程,相輔相成。session保存在伺服器,cookie保存在客戶端。最常見的做法就是客戶端的cookie僅僅保存一個sessionID,這個sessionID是一個毫無規則的隨機數,由伺服器在客戶端登錄通過後隨機生產的。往後,客戶端每次訪問該網站都要帶上這個由sessionID組成的cookie。伺服器收到請求,首先拿到客戶端的sessionID,然後從伺服器內存中查詢它所代表的客戶端(用戶名,用戶組,有哪些許可權等)。

與token相比,這里的重點是,伺服器必須保存sessionID以及該ID所代表的客戶端信息。這些內容可以保存在內存,也可以保存到資料庫(通常是內存資料庫)。

而token則可以伺服器完全不用保存任何登錄信息。

token的流程是這樣的。客戶端登錄通過後,伺服器生成一堆客戶端身份信息,包括用戶名、用戶組、有那些許可權、過期時間等等。另外再對這些信息進行簽名。之後把身份信息和簽名作為一個整體傳給客戶端。這個整體就叫做token。之後,客戶端負責保存該token,而伺服器不再保存。客戶端每次訪問該網站都要帶上這個token。伺服器收到請求後,把它分割成身份信息和簽名,然後驗證簽名,若驗證成功,就直接使用身份信息(用戶名、用戶組、有哪些許可權等等)。

可以看出,相對於cookie/session機制,token機制中,伺服器根本不需要保存用戶的身份信息(用戶名、用戶組、許可權等等)。這樣就減輕了伺服器的負擔。

我們舉個例來說,假如目前有一千萬個用戶登錄了,在訪問不同的網頁。如果用cookie/session,則伺服器內存(或內存資料庫)中要同時記錄1千萬個用戶的信息。每次客戶端訪問一個頁面,伺服器都要從內存中查詢出他的登錄信息。而如果用token,則伺服器內存中不記錄用戶登錄信息。它只需要在收到請求後,直接使用客戶端發過來的登錄身份信息。

可以這么說, cookie/session是伺服器說客戶端是誰,客戶端才是誰。而token是客戶端說我(客戶端)是誰,我就是誰 。當然了,token是有簽名機制的。要是客戶端偽造身份,簽名通不過。這個簽名演算法很簡單,就是將客戶端的身份信息加上一個只有伺服器知道的鹽值(不能泄露),然後進行md5散列演算法(這里只是簡化,方便理解,實際細節要稍復雜一些)。

cookie/session在單伺服器,單域名時比較簡單,否則的話,就要考慮如何將客戶端的session保存或同步到多個伺服器。還要考慮一旦宕機,內存中的這些信息是否會丟失。token因為伺服器不保存用戶身份,就不存在這個問題。這是token的優點。

token因為伺服器不保存用戶身份信息,一切都依賴當初那個簽名。所以存在被盜用的風險。也就是說一旦盜用,伺服器可能毫無辦法,因為它只認簽名演算法。而session機制,伺服器看誰不爽,可以隨時把他踢出(從內存中刪掉)。正是因為如此,token高度依賴過期時間。過期時間不能太長。過期短,可以減少被盜用的風險。

除了上面所說的,我個人認為,如果開發的系統足夠小,傾向於使用cookie/session。如果系統同時登錄用戶多,集群伺服器多,有單點登錄需求,則傾向於使用token。

萬維網的發展 歷史

Token, 令牌,代表執行某些操作的權利的對象。

token主要用於鑒權使用,主要有以下幾類:

cookie主要是網站用於在瀏覽器臨時存放的數據,包括瀏覽器緩存數據以及伺服器設定的一些數據,主要存放在瀏覽器端。


session主要用於保存會話數據,一般存儲在伺服器端,同時每一條session對用一個sessionID,sessionID是存放在瀏覽器的cookie中。


傳統上的會話登陸和鑒權主要用session加cookie實現,隨著分布式系統的快速演進,尤其是微服務的應用,token+cookie的授權訪問機製得到親睞,通常在用戶登錄後,伺服器生成訪問令牌(Access token),瀏覽器存儲cookie中,在每次請求資源時都會在請求頭中帶上token,用於伺服器授權訪問使用。

Token和session都是web網站的會話保持、認證的解決方案;

既然都一樣為什麼還有token的說法。

從token產生的背景說起

1.移動端應用使得伺服器端Session失效

2.分布式系統中Session無法共享

所以說session對於以上兩種情況無效了,所以有了Token的說法

那麼什麼是token,token長什麼樣子?

先給大家一個直觀的感受

token:PC-3066014fa0b10792e4a762-23-20170531133947-4f6496

說白了token保存就是用戶的信息(不能保存密碼等敏感信息)

token的組成:

客戶端標識-USERCODE-USERID-CREATIONDATE-RONDEM[6位]

USERCODE,RONDEM[6位]經過MD5加密就變成了以上字元串

token的請求流程

請求流程解析

1.前端用戶發送登錄信息至認證系統

2.驗證用戶登錄信息,判斷用戶是否存在

3.如果用戶存在,生成token信息(客戶端標識-USERCODE-USERID-CREATIONDATE-RONDEM[6位]),並存儲在redis中

4.並將該token返回前端,附加至header

驗證token

客戶端

將token附加至header

服務端

最後總結一下

一般的垂直架構項目使用Session沒有任何問題,但是分布式項目或涉及到移動端則考慮使用token。

session

session的中文翻譯是「會話」,當用戶打開某個web應用時,便與web伺服器產生一次session。伺服器使用session把用戶的信息臨時保存在了伺服器上,用戶離開網站後session會被銷毀。這種用戶信息存儲方式相對cookie來說更安全,可是session有一個缺陷:如果web伺服器做了負載均衡,那麼下一個操作請求到了另一台伺服器的時候session會丟失。

cookie

cookie是保存在本地終端的數據。cookie由伺服器生成,發送給瀏覽器,瀏覽器把cookie以kv形式保存到某個目錄下的文本文件內,下一次請求同一網站時會把該cookie發送給伺服器。由於cookie是存在客戶端上的,所以瀏覽器加入了一些限制確保cookie不會被惡意使用,同時不會占據太多磁碟空間,所以每個域的cookie數量是有限的。

cookie的組成有:名稱(key)、值(value)、有效域(domain)、路徑(域的路徑,一般設置為全局:"")、失效時間、安全標志(指定後,cookie只有在使用SSL連接時才發送到伺服器(https))。下面是一個簡單的js使用cookie的例子:

用戶登錄時產生cookie:

document.cookie = "id="+result.data['id']+"; path=/";

document.cookie = "name="+result.data['name']+"; path=/";

document.cookie = "avatar="+result.data['avatar']+"; path=/";

使用到cookie時做如下解析:

var cookie = document.cookie;var cookieArr = cookie.split(";");var user_info = {};for(var i = 0; i < cookieArr.length; i++) {

user_info[cookieArr[i].split("=")[0]] = cookieArr[i].split("=")[1];

}

$('#user_name').text(user_info[' name']);

$('#user_avatar').attr("src", user_info[' avatar']);

$('#user_id').val(user_info[' id']);

token

token的意思是「令牌」,是用戶身份的驗證方式,最簡單的token組成:uid(用戶唯一的身份標識)、time(當前時間的時間戳)、sign(簽名,由token的前幾位+鹽以哈希演算法壓縮成一定長的十六進制字元串,可以防止惡意第三方拼接token請求伺服器)。還可以把不變的參數也放進token,避免多次查庫

cookie 和session的區別

1、cookie數據存放在客戶的瀏覽器上,session數據放在伺服器上。

2、cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙

考慮到安全應當使用session。

3、session會在一定時間內保存在伺服器上。當訪問增多,會比較佔用你伺服器的性能

考慮到減輕伺服器性能方面,應當使用COOKIE。

4、單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。

5、所以個人建議:

將登陸信息等重要信息存放為SESSION

其他信息如果需要保留,可以放在COOKIE中

token 和session 的區別

session 和 oauth token並不矛盾,作為身份認證 token安全性比session好,因為每個請求都有簽名還能防止監聽以及重放攻擊,而session就必須靠鏈路層來保障通訊安全了。如上所說,如果你需要實現有狀態的會話,仍然可以增加session來在伺服器端保存一些狀態

App通常用restful api跟server打交道。Rest是stateless的,也就是app不需要像browser那樣用cookie來保存session,因此用session token來標示自己就夠了,session/state由api server的邏輯處理。 如果你的後端不是stateless的rest api, 那麼你可能需要在app里保存session.可以在app里嵌入webkit,用一個隱藏的browser來管理cookie session.

Session 是一種HTTP存儲機制,目的是為無狀態的HTTP提供的持久機制。所謂Session 認證只是簡單的把User 信息存儲到Session 里,因為SID 的不可預測性,暫且認為是安全的。這是一種認證手段。 而Token ,如果指的是OAuth Token 或類似的機制的話,提供的是 認證 和 授權 ,認證是針對用戶,授權是針對App 。其目的是讓 某App有權利訪問 某用戶 的信息。這里的 Token是唯一的。不可以轉移到其它 App上,也不可以轉到其它 用戶 上。 轉過來說Session 。Session只提供一種簡單的認證,即有此 SID,即認為有此 User的全部權利。是需要嚴格保密的,這個數據應該只保存在站方,不應該共享給其它網站或者第三方App。 所以簡單來說,如果你的用戶數據可能需要和第三方共享,或者允許第三方調用 API 介面,用 Token 。如果永遠只是自己的網站,自己的 App,用什麼就無所謂了。

token就是令牌,比如你授權(登錄)一個程序時,他就是個依據,判斷你是否已經授權該軟體;cookie就是寫在客戶端的一個txt文件,裡麵包括你登錄信息之類的,這樣你下次在登錄某個網站,就會自動調用cookie自動登錄用戶名;session和cookie差不多,只是session是寫在伺服器端的文件,也需要在客戶端寫入cookie文件,但是文件里是你的瀏覽器編號.Session的狀態是存儲在伺服器端,客戶端只有session id;而Token的狀態是存儲在客戶端。

想要全面深入地掌握Token,我們需要先了解這些:Token的概念、身份驗證過程、實現思路、使用場景,以及Cookie、Session、Token的區別。


內容綱要


Token的定義

Token是驗證用戶身份的一種方式,簡稱做「令牌」。最簡單的token組成:uid(用戶唯一的身份標識)、time(當前時間的時間戳)、sign(簽名,由token的前幾位+鹽,以哈希演算法壓縮成一定長的十六進制字元串,可以防止惡意第三方拼接token請求伺服器)。還可以把不變的參數也放進token,避免多次查庫。


Token的身份驗證過程

每一次請求都需要Token,Token應該在HTTP的頭部發送,從而保證Http請求無狀態。我們同樣通過設置伺服器屬性Access-Control-Allow-Origin:* ,讓伺服器能接受到來自所有域的請求。

需要注意的是,在ACAO頭部標明(designating)*時,不得帶有像HTTP認證,客戶端SSL證書和cookies的證書。


Token的實現思路


當我們在程序中認證了信息,並取得Token之後,我們便能通過這個Token做許多的事情。我們甚至能基於創建一個基於許可權的token傳給第三方應用程序,這些第三方程序能夠獲取到我們的數據(當然只有在我們允許的特定的token)。


Token的應用場景

Cookie和Session的區別

綜合以上考量,建議方案:

Session和Cookie取長補短、配合使用,將登陸信息等重要信息存放為Session,其他信息如果需要保留,可以放在Cookie中。


Token 和 Session 的區別

Session和Token並不矛盾,作為身份認證,Token安全性比Session高,因為Token發送的每個請求都帶有簽名,能防止監聽,以及重放攻擊。而session就必須靠鏈路層來保障通訊安全。如上所說,如果需要實現有狀態的會話,可以通過增加session,在伺服器端保存一些狀態。


App通常用Restful API跟server打交道。Rest是Stateless的,也就是App不需要像Browser那樣用Cookie來保存Session,因此使用Session Token來標示就足夠了。Session/state由API Server的邏輯處理。如果後端不是Stateless的rest API,那麼可能需要在App里保存Session,可以在App里嵌入webkit,用一個隱藏的Browser來管理Cookie Session.


Session是一種HTTP存儲機制,目的是為無狀態的HTTP提供持久機制。 所謂的Session認證,只是簡單的把User信息存儲到Session里,因為SID的不可預測性,暫且認為是安全的,這是一種認證手段。


Session只提供一種簡單的認證,即有此SID,以及User的全部權利。是需要嚴格保密的,這個數據只在使用站點保存,不可共享給其它網站或者第三方App。所以簡單來說,如果你的用戶數據可能需要和第三方共享,或者允許第三方調用API介面,則使用Token,如果只是自己的網站或App應用,使用什麼都OK。


Token,指的是OAuth Token或類似的機制的話,提供的是認證和授權 ,認證是針對用戶,授權是針對App。其目的是讓某App有權利訪問某用戶的信息,這里的Token是唯一的,不可以轉移到其它App上,也不可以轉到其它用戶上。


Token就是令牌,比如你授權(登錄)一個程序時,他就是個依據,判斷你是否已經授權該軟體。Cookie就是寫在客戶端的一個txt文件,記錄下用戶的訪問、登錄等信息,下次用戶再登錄某個網站時,伺服器接收到請求,就會自動調用Cookie,自動登錄用戶名。


Session和Cookie差不多,只是Session是寫在伺服器端的文件,也需要在客戶端寫入Cookie文件,但是文件里是用戶的瀏覽器編號.Session的狀態是存儲在伺服器端,客戶端只有session id,而Token的狀態是存儲在客戶端的。


以上,是關於Token、Session、Cookie的知識點介紹,更加深入的詳解,感興趣的童鞋,可查看我持續分享的【BAT架構技術專題合集500+】,回復【架構】,即可領取。


Token是什麼?

Token是令牌、憑證、鑰匙,在Web領域中進行 身份驗證 ,關鍵點在驗證!!,說驗證就必須了解一下Web領域的發展史呢。

2. 隨著人們需求的改變,比如在線購物系統,需要登陸的網站等,這時候需要進行 交互 性,伺服器接收到請求的時候,要根據你是否登陸,以及判斷你是誰,來給你響應,這時候問題就來了,怎麼知道每次請求的誰呢,所以就出來了一個 會話標識(session id),就是一個隨機的字元串 ,每個人登陸的時候,伺服器都會返回一個會話標識,這是再請求的時候,只要帶上會話標識,伺服器就知道請求的是誰。

3. 這樣子每個人只要保存自己的session id就可以啦,伺服器要保存 所有人 的session id!!!如果有成千上萬的人訪問伺服器,那對伺服器是巨大的開銷,嚴重限制了伺服器端的擴展能力,比如機器A跟機器B組成了伺服器集群,那麼訪問了機器A,會話標識在機器A上,如果轉到機器B,就不能訪問了,也許會說,那復制呢,機器A搬到機器B,也有說統一把標識放在一個機器上,但是萬一這個機器掛了呢,那體驗就很差了。

4. 這個時候就有人想,用戶自己保存自己的標識,就是Token,訪問的時候帶上這個Token,這個 Token是用戶id+簽名 ,驗證時,伺服器只要相同的演算法和伺服器才知道的密鑰進行簽名,如果結果跟Token中的簽名一樣,那就可以證明是登陸過的用戶。

這樣一來,伺服器不保存session id,只要生成Token,訪問時,只要對Token進行判斷,Token也是有有效期的,所以也要進行refreshToken的。

Token,Cookie,Session三者使用場景的區別?

Token主要是Web領域的身份認證 ,最常見的就是Web API這個功能:

Cookie 就是餅干, 它是伺服器生產,永久保存在瀏覽器的數據,以kv的形式 ,你可以打開你的瀏覽器(這里以win10 edge為例),點擊上方的三個點的按鈕,再點擊更多工具,再點擊開發人員工具,再點擊網路,此時內容選擇文檔,然後刷新頁面,找Cookie即可。


Session是會話標識,是伺服器用來判斷正在會話的用戶是誰,伺服器生產的隨機數 ,保存在伺服器中,用戶端也要進行保存,雖然能實現會話的共能,但對伺服器的擴展能力限制,同時當伺服器是兩台機器組成以上的時候,會導致兩台機器以上保存的session同步問題,會導致用戶體驗極差。


Token跟Session最大的區別就是Token服務端不用保存,同時是通過簽名等技術實現的,Session因為是隨機數,導致伺服器要進行保存。

8. Token 原理解讀

上一篇文章我們了解了一下 cookie 與 session 的產生、作用與原理。盡管二者在歷史中已經服役過很長一段時間,但不論什麼技術,都會有後來的優秀者取而代之。

前面說到,cookie 因為是保存在客戶端,所以有安全隱患,因而誕生了 session,session 保存在伺服器端,相對安全很多。但 session 每次都要為用戶開辟一個空間用於其身份校驗,且每次瀏覽器的請求過來伺服器都要進行校驗請求,十分耗費伺服器的空間與性能。

於是,另一種身份校驗工具誕生了,這就是 token。

本質上還是用戶身份驗證的工具。但與 cookie、session 明文似的形式不同,token 是經過一系列加密手段加密過的,最後表現為一串「無意義」的字元串。但裡麵包含了許多信息,可能包括用戶登錄的終端的地址、用戶身份 ID、時間戳以及一個簽名。所謂簽名就是信息發送者給這段信息進行簽名,讓信息接收方知道請求 token 是屬於誰。可以理解為在你的身份證上簽名字,證件加筆跡雙重認證。

為了避免上述 CSRF 攻擊,瀏覽器對網頁資源的訪問提出了限制,URL 請求必須是與頁面一樣來自同一 協議 域名 才給予訪問許可權。這樣三者相同的站點被認為是有相同的「源」,是一個獨立的「域」。即使 「localhost」 與 「ip」 都指向了本機,但也會被認為是非同源。瀏覽器在某個「域」下不會執行其他「域」的腳本。因而這也產生了前端領域里一個重要的話題:跨域。

session 的產生來自於用戶登錄後伺服器生成的一個 session 對象,保存在伺服器端,這個 session 只適用於該「域」。但實際情況是,一個網站的請求大多數情況下都會跨域,每台伺服器的埠不同,甚至是域名就不同,每當跨域時就會形成新的會話,生成新的 session,這是非常影響用戶體驗的,所以也會有許多保存、共享或中央存儲 session 的方案。

但上述兩種限制在 token 這里就不再是問題。

與 cookie 類似。

首先,用戶輸入賬號密碼,發起登錄請求,伺服器校驗賬號密碼合法性,成功則返回 token 給客戶端。

客戶端收到響應後拿到 token,將其通過 localStorage 等本地存儲方式進行保存。

當瀏覽器再次請求時,需要在請求頭中添加 token,這樣伺服器在接收到請求後便可以識別該請求的身份是否合法,合法則返回響應數據。

在實際應用中,配合 axios 的請求攔截器使用起來會很方便:

這樣,就不用每次請求都手動添加 token,axios 會自動幫助我們完成添加,十分方便。

其實前端程序員對 token 的涉及沒有多深,只需要在需要授權的請求中攜帶 token 即可。token 的生成、加密等都是後端去處理。所以,這里也就不在贅述 token 的加密原理,以筆者的能力也很難去講述清楚。

token 運用也不是上文中描述的那麼簡單,涉及到一些過期處理、refresh 等操作。這些日後有機會再詳談。

9. 前後端分離項目——登錄Token校驗思路

對token的校驗分為前端和後端

前端: Vue-Cli 2.x + axios
後端:SpringBoot 2.3.4

這里的話,userToken和userId放到sessionStorage是關鍵步驟

後端主要是使用攔截器來進行請求的攔截和校驗

解釋一下思路:

這里的話,針對需要攔截的路徑和需要放行的路徑進行配置就行
關於redisTemple的引入這里就不再贅述。
到這里為止,前後端的token就都做完了,後面就再講講前端的一些其他思路吧
對於登錄狀態的判斷,前端可以在router.foreach上對路由進行狀態判定,從而實現頁面程度的攔截(具體可以參考最後的參考文章2)

在使用攔截器後,會發現前端部分請求會無法正常到達後端,網路後發現是因為 axios發送正式請求前會先發送一個嗅探請求 ,而嗅探請求是不攜帶我們封裝的header的,所以會導致部分請求會無法成功,解決的方式有很多種,這里的話是選擇了在後端去直接處理

參考文章
1、SpringBoot加了攔截器後出現的跨域問題解析
https://blog.csdn.net/mrkorbin/article/details/104066979
2、Vue項目中實現用戶登錄及token驗證
https://www.cnblogs.com/web-record/p/9876916.html

10. Vue項目中用戶登錄及token驗證及流程圖

在前後端完全分離的情況下,Vue項目中實現token驗證大致思路如下:

簡單舉例說明:

① 調登錄介面成功,在回調函數中將token存儲到localStorage和vuex中(login.vue中)

② store文件夾下的index.js

③ 路由守衛(router文件夾下的index.js)

④ 請求頭加token

⑤ 如果前端拿到狀態碼為401,就清除token信息並跳轉到登錄頁面

流程圖: