圖文詳解應用登陸驗證碼的多種實現方案

file

在本號的一系列Spring Security文章中,前後介紹了各類登陸驗證及受權中的知識點,如:spring-security簡介並與shiro對比、 formLogin模式登陸認證、動態數據登陸驗證與權限分配、帳戶屢次登陸失敗鎖定、RememberMe記住我功能,等等文章。筆者以爲以上的這些實際上都很簡單,咱們沒有涉及到分佈式應用。本節將以分佈式的應用背景,講解驗證碼實現的多種方式。本小節先從理論的角度爲你們講解,具體實現筆者還會再寫。前端

  • session存儲驗證碼,不適用於分佈式應用
  • 共享session存儲驗證碼,適用於分佈式應用
  • 基於對稱算法的驗證碼,適用於分佈式應用

1、驗證碼的組成部分

驗證碼實際上和謎語有點像,分爲謎面和謎底。謎面一般是圖片,謎底一般爲文字。謎面用於展示,謎底用於校驗。nginx

  • 對於字符型驗證碼。好比:謎面是顯示字符串"ABGH"的圖片,謎底是字符串"ABGH"
  • 對於計算類驗證碼。好比:謎面是「1+1=」的圖片,謎底是「2」
  • 對於拖拽類的驗證碼。好比:謎面是一個拖拽式的拼圖,謎底是拼圖位置的座標

總之,無論什麼形式的謎面,最後用戶的輸入內容要和謎底進行驗證。redis

2、session存儲驗證碼

圖中藍色爲服務端、澄粉色爲客戶端。算法

file

這是一種最典型的驗證碼實現方式,實現方式也比較簡單。spring

  • 應用服務端隨機的生成驗證碼文字
  • 將驗證碼文字存到session裏面
  • 根據驗證碼文字生成驗證碼圖片,響應給客戶端
  • 檢查用戶輸入的內容與驗證碼謎底是否一致

這種實現方式的優勢就是比較簡單,缺點就是:由於一套應用部署一個session,當咱們把應用部署多套如:A、B、C,他們各自有一個session而且不共享。致使的結果就是驗證碼和圖片由A生成,可是驗證請求發送到了B,這樣就不可能驗證經過。數據庫

3、共享session存儲驗證碼

在第二小節講到的問題,實際上不是驗證碼的問題,而是如何保證session惟一性或共享性的問題。主要的解決方案有兩種:segmentfault

file

  • 一般咱們實現負載均衡應用的前端都是使用nginx或者haproxy,兩者均可以配置負載均衡策略。其中一種策略就是:你的客戶端ip上一次請求的是A應用,你的下一次請求還轉發給A應用。這樣就保證了session的惟一性。可是這種方式有可能會致使A、B、C應用其中一個或兩個分配了大量的請求,而另一個處理不多的請求,致使負載並不均衡。
  • 另一種很是通用的方式就是將分佈式應用的session統一管理,也就是說原來A、B、C各自的session都存在本身的內存中,如今更改成統一存儲到一個地方,你們一塊兒用。這樣就實現了session的惟一和共享,是實現分佈式應用session管理的有效途徑。在Spring框架內,最成熟的解決方案就是spring session + redis 。可自行參考實現。

4、基於對稱算法的驗證碼

可能出於主機資源的考慮,可能出於系統架構的考量,有些應用是無狀態的。安全

  • 什麼是無狀態應用:就是不保存用戶狀態的應用。
  • 什麼是用戶狀態:好比當你登錄以後,在session中保存的用戶的名稱、組織等等信息。
  • 因此能夠簡單的理解,無狀態應用就是無session應用。固然這並不徹底準確。

那麼對於這些無狀態的應用,咱們就沒法使用session,或者換個說法從團隊開發規範上就不讓使用session。那麼咱們的驗證碼該怎麼作?springboot

file

  • 一樣,首先要生成隨機的驗證碼(謎底),可是不作任何存儲操做
  • 將謎底(驗證碼文字)加上時間串、應用信息等組成一個字符串進行加密。必須是對稱加密,也就是說能夠解密的加密算法。
  • 生成驗證碼圖片,並與加密後的密文,經過cookies一併返回給客戶端。
  • 當用戶輸入驗證碼提交登陸以後,服務端解密cookies中的密文(主要是驗證碼文字),與用戶的輸入進行驗證比對。

這種作法的缺陷是顯而易見的:實際上就是將驗證碼文字在客戶端服務端之間走了一遍。雖然是加密後的驗證碼文字,可是有加密就必須有解密,不然沒法驗證。因此更爲穩妥的作法是爲每個用戶生成密鑰,並將密鑰保存到數據庫裏面,在對應的階段內調用密鑰進行加密或者解密。cookie

從密碼學的角度講,沒有一種對稱的加密算法是絕對安全的。因此更重要的是保護好你的密鑰。正如沒有一把鎖頭是絕對安全的,更重要的是保護好你的鑰匙。

期待您的關注

相關文章
相關標籤/搜索