前端面試查漏補缺--(十) 前端鑑權

前言

本系列最開始是爲了本身面試準備的.後來發現整理愈來愈多,差很少有十二萬字符,最後決定仍是分享出來給你們.html

爲了分享整理出來,花費了本身大量的時間,起碼是隻本身用的三倍時間.若是喜歡的話,歡迎收藏,關注我!謝謝!前端

文章連接

合集篇:

前端面試查漏補缺--Index篇(12萬字符合集) 包含目前已寫好的系列其餘十幾篇文章.後續新增值文章不會再在每篇添加連接,強烈建議議點贊,關注合集篇!!!!,謝謝!~vue

後續更新計劃

後續還會繼續添加設計模式,前端工程化,項目流程,部署,閉環,vue常考知識點 等內容.若是以爲內容不錯的話歡迎收藏,關注我!謝謝!ios

求一分內推

目前本人也在準備跳槽,但願各位大佬和HR小姐姐能夠內推一份靠譜的武漢 前端崗位!郵箱:bupabuku@foxmail.com.謝謝啦!~web

常見鑒權方式

目前咱們經常使用的鑑權有四種:面試

  1. HTTP Basic Authentication (HTTP基本認證)
  2. session-cookie
  3. Token 驗證(包括JWT,SSO)
  4. OAuth(開放受權)

HTTP Basic Authentication

這種認證方式是瀏覽器遵照http協議實現的基本受權方式,HTTP協議進行通訊的過程當中,HTTP協議定義了基本認證認證容許HTTP服務器對客戶端進行用戶身份證的方法。ajax

目前基本沒有再使用這種認證方式的,一些老項目的內網認證可能還會有.redis

這裏大概提一下驗證過程,主要參考這篇文章算法

認證過程:   1. 客戶端向服務器請求數據,請求的內容多是一個網頁或者是一個ajax異步請求,此時,假設客戶端還沒有被驗證,則客戶端提供以下請求至服務器:數據庫

  Get /index.html HTTP/1.0 
  Host:www.google.com
複製代碼

2. 服務器向客戶端發送驗證請求代碼401,(WWW-Authenticate: Basic realm=」google.com」這句話是關鍵,若是沒有客戶端不會彈出用戶名和密碼輸入界面)服務器返回的數據大抵以下:

  HTTP/1.0 401 Unauthorised 
  Server: SokEvo/1.0 
  WWW-Authenticate: Basic realm=」google.com」 
  Content-Type: text/html 
  Content-Length: xxx
複製代碼

3. 當符合http1.0或1.1規範的客戶端(如IE,FIREFOX)收到401返回值時,將自動彈出一個登陸窗口,要求用戶輸入用戶名和密碼。

4. 用戶輸入用戶名和密碼後,將用戶名及密碼以BASE64加密方式加密(base64不安全!),並將密文放入前一條請求信息中,則客戶端發送的第一條請求信息則變成以下內容:

  Get /index.html HTTP/1.0 
  Host:www.google.com 
  Authorization: Basic d2FuZzp3YW5n
複製代碼

注:d2FuZzp3YW5n表示加密後的用戶名及密碼(用戶名:密碼 而後經過base64加密,加密過程是瀏覽器默認的行爲,不須要咱們人爲加密,咱們只須要輸入用戶名密碼便可)

5. 服務器收到上述請求信息後,將Authorization字段後的用戶信息取出、解密,將解密後的用戶名及密碼與用戶數據庫進行比較驗證,如用戶名及密碼正確,服務器則根據請求,將所請求資源發送給客戶端

效果:
客戶端未未認證的時候,會彈出用戶名密碼輸入框,這個時候請求時屬於pending狀態, 這個時候其實服務當用戶輸入用戶名密碼的時候客戶端會再次發送帶Authentication頭的請求。

session-cookie

這個方式是利用服務器端的session(會話)和瀏覽器端的cookie來實現先後端的認證,因爲http請求時是無狀態的,服務器正常狀況下是不知道當前請求以前有沒有來過,這個時候咱們若是要記錄狀態,就須要在服務器端建立一個會話(session),將同一個客戶端的請求都維護在各自得會會話中,每當請求到達服務器端的時候,先去查一下該客戶端有沒有在服務器端建立session,若是有則已經認證成功了,不然就沒有認證。

認證過程:

1,服務器在接受客戶端首次訪問時在服務器端建立session,而後保存session(咱們能夠將session保存在內存中,也能夠保存在redis中,推薦使用後者),而後給這個session生成一個惟一的標識字符串,而後在響應頭中種下這個惟一標識字符串。

2.簽名。這一步只是對sid進行加密處理,服務端會根據這個secret密鑰進行解密。(非必需步驟)

3.瀏覽器中收到請求響應的時候會解析響應頭,而後將sid保存在本地cookie中,瀏覽器在下次http請求的請求頭中會帶上該域名下的cookie信息,

4.服務器在接受客戶端請求時會去解析請求頭cookie中的sid,而後根據這個sid去找服務器端保存的該客戶端的session,而後判斷該請求是否合法。

弊端:

  • 服務器內存消耗大: 用戶每作一次應用認證,應用就會在服務端作一次記錄,以方便用戶下次請求時使用,一般來說session保存在內存中,隨着認證用戶的增長,服務器的消耗就會很大.
  • 易受到CSRF攻擊: 基於cookie的一種跨站僞造攻擊, 基於cookie來進行識別用戶的話,用戶自己就攜帶了值,cookie被截獲,用戶就很容易被僞造.

Token驗證

概念

token是用戶身份的驗證方式,咱們一般叫它:令牌。當用戶第一次登陸後,服務器生成一個token並將此token返回給客戶端,之後客戶端只需帶上這個token前來請求數據便可,無需再次帶上用戶名和密碼。

最簡單的token組成:uid(用戶惟一的身份標識)、time(當前時間的時間戳)、sign(簽名,由token的前幾位+鹽以哈希算法壓縮成必定長的十六進制字符串,能夠防止惡意第三方拼接token請求服務器)。還能夠把不變的參數也放進token,避免屢次查庫。

咱們能夠把Token想象成一個安全的護照。你在一個安全的前臺驗證你的身份(經過你的用戶名和密碼),若是你成功驗證了本身,你就能夠取得這個。當你走進大樓的時候(試圖從調用API獲取資源),你會被要求驗證你的護照,而不是在前臺從新驗證。

驗證流程

大概的流程是這樣的:

  • 1, 客戶端使用用戶名跟密碼請求登陸
  • 2, 服務端收到請求,去驗證用戶名與密碼
  • 3, 驗證成功後,服務端會簽發一個 Token,再把這個 Token 發送給客戶端
  • 4, 客戶端收到 Token 之後能夠把它存儲起來,好比放在 Cookie 裏或者 Local Storage 裏
  • 5, 客戶端每次向服務端請求資源的時候須要帶着服務端簽發的 Token
  • 6, 服務端收到請求,而後去驗證客戶端請求裏面帶着的 Token,若是驗證成功,就向客戶端返回請求的數據

總的來講就是客戶端在首次登錄之後,服務端再次接收http請求的時候,就只認token了,請求只要每次把token帶上就好了,服務器端會攔截全部的請求,而後校驗token的合法性,合法就放行,不合法就返回401(鑑權失敗)。

Token優勢與缺點

優勢:

  • Token 徹底由應用管理,因此它能夠避開同源策略. (Cookie是不容許垮域訪問的,token不存在)
  • Token 能夠避免 CSRF 攻擊(也是由於不須要cookie了)
  • Token 能夠是無狀態的,能夠在多個服務間共享
  • Token 支持手機端訪問(Cookie不支持手機端訪問)

服務器只須要對瀏覽器傳來的token值進行解密,解密完成後進行用戶數據的查詢,若是查詢成功,則經過認證.因此,即時有了多臺服務器,服務器也只是作了token的解密和用戶數據的查詢,它不須要在服務端去保留用戶的認證信息或者會話信息,這就意味着基於token認證機制的應用不須要去考慮用戶在哪一臺服務器登陸了,這就爲應用的擴展提供了便利,解決了session擴展性的弊端。

缺點:

  • 佔帶寬: 正常狀況下token要比 session_id更大,須要消耗更多流量,擠佔更多帶寬.(不過幾乎能夠忽略)
  • 性能問題: 相比於session-cookie來講,token須要服務端花費更多的時間和性能來對token進行解密驗證.其實Token相比於session-cookie來講就是一個"時間換空間"的方案.

Token與session的區別

  • 1. 使用Token,服務端不須要保存狀態. 在session中sessionid 是一個惟一標識的字符串,服務端是根據這個字符串,來查詢在服務器端保持的session,這裏面才保存着用戶的登錄狀態。可是token自己就是一種登錄成功憑證,他是在登錄成功後根據某種規則生成的一種信息憑證,他裏面自己就保存着用戶的登錄狀態。服務器端只須要根據定義的規則校驗這個token是否合法就行。

  • 2. Token不須要藉助cookie的. session-cookie是須要cookie配合的,那麼在http代理客戶端的選擇上就只有瀏覽器了,由於只有瀏覽器纔會去解析請求響應頭裏面的cookie,而後每次請求再默認帶上該域名下的cookie。可是咱們知道http代理客戶端不僅有瀏覽器,還有原生APP等等,這個時候cookie是不起做用的,或者瀏覽器端是能夠禁止cookie的(雖然能夠,可是這基本上是屬於吃飽沒事幹的人乾的事),可是token 就不同,他是登錄請求在登錄成功後再請求響應體中返回的信息,客戶端在收到響應的時候,能夠把他存在本地的cookie,storage,或者內存中,而後再下一次請求的請求頭重帶上這個token就好了。簡單點來講cookie-session機制他限制了客戶端的類型,而token驗證機制豐富了客戶端類型。

  • 3. 時效性。session-cookie的sessionid實在登錄的時候生成的並且在登出事時一直不變的,在必定程度上安全就會低,而token是能夠在一段時間內動態改變的。

  • 4. 可擴展性。token驗證自己是比較靈活的,一是token的解決方案有許多,經常使用的是JWT,二來咱們能夠基於token驗證機制,專門作一個鑑權服務,用它向多個服務的請求進行統一鑑權。

Token過時與Refresh Token

Token過時:

token是訪問特定資源的憑證,出於安全考慮,確定是要有過時時間的。要否則一次登陸即可能一直使用,那token認證還有什麼意義? token可定是有過時時間的,通常不會很長,不會超高一個小時.

Refresh Token :

爲何須要refresh token?

若是token過時了,就要從新獲取。繼續重複第一次獲取token的過程(好比登陸,掃描受權等),每一小時就必須獲取一次! 這樣作是很是很差的用戶體驗。爲了解決這個問題,因而就有了refresh token.經過refresh token去從新獲取新的 token.

refresh token,也是加密字符串,而且和token是相關聯的。與獲取資源的token不一樣,refresh token的做用僅僅是獲取新的token,所以其做用和安全性要求都較低,因此其過時時間也能夠設置得長一些,能夠以天爲最小單位。固然若是refresh token過時了,仍是須要從新登陸驗證的.

JWT (JSON Web Tokens)

阮一峯老師這篇關於JWT的文章,真的是寫得很是好,也被不少人大段摘抄引用.對JWT不瞭解的同窗能夠直接查看這篇文章,我這裏就不copy了.這裏我只重點總結一下.

JWT原理

JWT 的原理是,服務器認證之後,生成一個 JSON 對象,發回給用戶.以後用戶與服務器通訊的時候.服務器徹底只靠這個對象認定用戶身份。爲了防止用戶篡改數據,服務器在生成這個對象的時候,會加上簽名

jwt最大的特色就是: 服務器就不保存任何 session 數據了,也就是說,服務器變成無狀態了,從而比較容易實現擴展。

JWT 的數據結構

它是一個很長的字符串,中間用點(.)分隔成三個部分。

分別是:Header(頭部).Payload(負載).Signature(簽名)

  • Header : 部分是一個 JSON 對象,描述 JWT 的元數據,例如:{ "alg": "HS256","typ": "JWT"}.alg屬性表示簽名的算法.默認是 HMAC SHA256(寫成 HS256);typ屬性表示這個令牌(token)的類型(type),JWT 令牌統一寫爲JWT。

頭部的 JSON 對象使用 Base64URL 算法轉成字符串。

  • Payload: 部分也是一個 JSON 對象,用來存放實際須要傳遞的數據。這個 JSON 對象也要使用 Base64URL 算法轉成字符串。

注意: JWT 默認是不加密的,任何人均可以讀到,因此不要把祕密信息放在這個部分。

  • Signature: 部分是對前兩部分的簽名,防止數據篡改。 首先,須要指定一個密鑰(secret)。這個密鑰只有服務器才知道,不能泄露給用戶。而後,使用 Header 裏面指定的簽名算法(默認是 HMAC SHA256).

JWT 的幾個特色

  • (1)JWT 默認是不加密,但也是能夠加密的。生成原始 Token 之後,能夠用密鑰再加密一次。
  • (2)JWT 不加密的狀況下,不能將祕密數據寫入 JWT。
  • (3)JWT 不只能夠用於認證,也能夠用於交換信息。有效使用 JWT,能夠下降服務器查詢數據庫的次數。
  • (4)JWT 的最大缺點是,因爲服務器不保存 session 狀態,所以沒法在使用過程當中廢止某個 token,或者更改 token的權限。也就是說,一旦 JWT 簽發了,在到期以前就會始終有效,除非服務器部署額外的邏輯。
  • (5)JWT 自己包含了認證信息,一旦泄露,任何人均可以得到該令牌的全部權限。爲了減小盜用,JWT的有效期應該設置得比較短。 對於一些比較重要的權限,使用時應該再次對用戶進行認證。
  • (6)爲了減小盜用,JWT 不該該使用 HTTP 協議明碼傳輸,要使用 HTTPS 協議傳輸。

首次登陸時,後端服務器判斷用戶帳號密碼正確以後,根據用戶id、用戶名、定義好的祕鑰、過時時間生成 token ,返回給前端; 前端拿到後端返回的 token ,存儲在 localStroage 和 Vuex 裏; 前端每次路由跳轉,判斷 localStroage 有無 token ,沒有則跳轉到登陸頁,有則請求獲取用戶信息,改變登陸狀態; 每次請求接口,在 Axios 請求頭裏攜帶 token; 後端接口判斷請求頭有無 token,沒有或者 token 過時,返回401; 前端獲得 401 狀態碼,重定向到登陸頁面。

補充: 後端主動讓JWT失效的方法

前面說過JWT一旦簽發了,就再也不收服務端控制了.由於它在服務端沒有記錄,是無狀態的,是它最大的優勢也是最大的缺點.這樣就會形成一種不可控性.

例如:若是用戶修改了,那他以前未到期的token怎麼廢棄掉???此時服務端是沒有記錄的,它是不知道哪些未到期的token是被廢棄了的.爲了解決這個問題,實際上是沒有完美的方法的! 都須要後端添加狀態,只是那種方法開銷最小.

目前常見的處理方法有:

  • 1,將 token 存入 DB(如 Redis)中,失效則刪除;但增長了一個每次校驗時候都要先從 DB 中查詢 token是否存在的步驟,並且違背了 JWT 的無狀態原則(不推薦)。
  • 2,維護一個 token 黑名單,失效則加入黑名單中(用的比較多)。
  • 3,在 JWT 中增長一個版本號字段,失效則改變該版本號。
  • 4,在服務端設置加密的 key 時,爲每一個用戶生成惟一的 key,失效則改變該 key。

這裏就簡單說下第二種方法:黑名單

  • 1,在簽發的jwt中payload加入一個爲隨機字符的字段token_id.
  • 2, 在服務端的分佈式緩存上保存一份「groupId」黑名單。若是用戶的jwt重置密碼等須要做廢已經簽發但未過時的jwt時,就將該以前用戶的「token__id」存入到黑名單中。並分配給他一個新的「token__id」到token中.
  • 3,存入到黑名單中的「token__id」會設置一個過時時間.過時後「token_id」自動從黑名單中刪除。
  • 4,全部須要作JWT有效性校驗的服務器,啓動時訪問分佈式緩存. 將黑名單下載到本地內存。而且訂閱分佈式緩存的消息推送功能,在黑名單發生增刪的時候,接收推送消息同步修改內存中的黑名單列表。
  • 5,服務器作JWT校驗的時候,除了校驗過時時間,還要查詢內存中的黑名單列表。若在黑名單中,則斷定該JWT爲失效。

雖然黑名單仍是作了分佈式存儲,但黑名單自己的體積和使用頻率卻很低,因此開銷很小.

單點登陸

概念

單點登陸(Single Sign On),簡稱爲 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統。

SSO通常都須要一個獨立的認證中心(passport),子系統的登陸均得經過passport,子系統自己將不參與登陸操做,當一個系統成功登陸之後,passport將會頒發一個令牌給各個子系統,子系統能夠拿着令牌會獲取各自的受保護資源,爲了減小頻繁認證,各個子系統在被passport受權之後,會創建一個局部會話,在必定時間內能夠無需再次向passport發起認證

單點登陸流程

  • 用戶訪問系統1的受保護資源,系統1發現用戶未登陸,跳轉至sso認證中心,並將本身的地址做爲參數
  • sso認證中心發現用戶未登陸,將用戶引導至登陸頁面
  • 用戶輸入用戶名密碼提交登陸申請
  • sso認證中心校驗用戶信息,建立用戶與sso認證中心之間的會話,稱爲全局會話,同時建立受權令牌
  • sso認證中心帶着令牌跳轉會最初的請求地址(系統1)
  • 系統1拿到令牌,去sso認證中心校驗令牌是否有效
  • sso認證中心校驗令牌,返回有效,註冊系統1
  • 系統1使用該令牌建立與用戶的會話,稱爲局部會話,返回受保護資源
  • 用戶訪問系統2的受保護資源
  • 系統2發現用戶未登陸,跳轉至sso認證中心,並將本身的地址做爲參數
  • sso認證中心發現用戶已登陸,跳轉回系統2的地址,並附上令牌
  • 系統2拿到令牌,去sso認證中心校驗令牌是否有效
  • sso認證中心校驗令牌,返回有效,註冊系統2
  • 系統2使用該令牌建立與用戶的局部會話,返回受保護資源

用戶登陸成功以後,會與sso認證中心及各個子系統創建會話,用戶與sso認證中心創建的會話稱爲全局會話,用戶與各個子系統創建的會話稱爲局部會話,局部會話創建以後,用戶訪問子系統受保護資源將再也不經過sso認證中心,全局會話與局部會話有以下約束關係

  • 局部會話存在,全局會話必定存在
  • 全局會話存在,局部會話不必定存在
  • 全局會話銷燬,局部會話必須銷燬

註銷:

sso認證中心一直監聽全局會話的狀態,一旦全局會話銷燬,監聽器將通知全部註冊系統執行註銷操做。

  • 用戶向系統1發起註銷請求
  • 系統1根據用戶與系統1創建的會話id拿到令牌,向sso認證中心發起註銷請求
  • sso認證中心校驗令牌有效,銷燬全局會話,同時取出全部用此令牌註冊的系統地址
  • sso認證中心向全部註冊系統發起註銷請求
  • 各註冊系統接收sso認證中心的註銷請求,銷燬局部會話
  • sso認證中心引導用戶至登陸頁面

OAuth 2.0

OAuth即開發受權,其實和SSO比較像.它容許用戶受權第三方網站訪問他們存儲在另外的服務提供者上的信息,而不須要將用戶名和密碼提供給第三方網站或分享他們數據的全部內容,爲了保護用戶數據的安全和隱私,第三方網站訪問用戶數據前都須要顯式的向用戶徵求受權。咱們常見的提供OAuth認證服務的廠商有QQ,微信,微博等。

限於篇幅,這裏推薦仍是阮一峯老師的文章

感謝及參考

相關文章
相關標籤/搜索