基于 Flask 設(shè)計 RESTful 的認證

最近在逛網(wǎng)站看到 flask + vue.js 前后端分離,就開始做了個小 demo , 考慮到交互安全性的問題,就使用 Flask 設(shè)計 RESTful 的認證和前端交互數(shù)據(jù),廢話不哆嗦,如下看:

數(shù)據(jù)庫
為了讓給出的示例看起來像真實的項目,這里我將使用 Flask-SQLAlchemy 來構(gòu)建用戶數(shù)據(jù)庫模型并且存儲到數(shù)據(jù)庫中(這里我用的是 MYSQL ,你也可以用其他的!)

用戶的數(shù)據(jù)庫模型是十分簡單的。對于每一個用戶,username 和 password 將會被存儲:

微信圖片_20171027162138.jpg

出于安全原因,用戶的原始密碼將不被存儲,密碼在注冊時被散列后存儲到數(shù)據(jù)庫中。使用散列密碼的話,如果用戶數(shù)據(jù)庫不小心落入惡意攻擊者的手里,他們也很難從散列中解析到真實的密碼。

密碼散列
為了創(chuàng)建密碼散列,我將會使用 werkzeug.security庫,一個專門用于密碼散列的 Python 包。
from werkzeug.security import generate_passwod_hash, check_passwod_hash


微信圖片_20171027162822.jpg

password() 函數(shù)接受一個明文的密碼作為參數(shù)并且存儲明文密碼的散列。當(dāng)一個新用戶注冊到服務(wù)器或者當(dāng)用戶修改密碼的時候,這個函數(shù)將被調(diào)用。

verify_password() 函數(shù)接受一個明文的密碼作為參數(shù)并且當(dāng)密碼正確的話返回 True 或者密碼錯誤的話返回 False。這個函數(shù)當(dāng)用戶提供和需要驗證憑證的時候調(diào)用。

你可能會問如果原始密碼散列后如何驗證原始密碼的?

散列算法是單向函數(shù),這就是意味著它們能夠用于根據(jù)密碼生成散列,但是無法根據(jù)生成的散列逆向猜測出原密碼。然而這些算法是具有確定性的,給定相同的輸入它們總會得到相同的輸出。

用戶注冊
Flask 中的路由實現(xiàn)

微信圖片_20171027163337.jpg

參數(shù) username 和 password 是從請求中攜帶的 JSON 數(shù)據(jù)中獲取,接著驗證它們。
如果參數(shù)通過驗證的話,新的 User 實例被創(chuàng)建。username 賦予給 User,接著使用 hash_password 方法散列密碼。用戶最終被寫入數(shù)據(jù)庫中。

用戶注冊這一塊在命令行出現(xiàn)了問題,找不到問題所在,就用來 Postman 注冊了

image.png

返回的信息是成功的!

image.png

基于密碼的認證
現(xiàn)在我們假設(shè)存在一個資源通過一個 API 暴露給那些必須注冊的用戶。這個資源是通過 URL: /api/resource 能夠訪問到。

為了保護這個資源,我們將使用 HTTP 基本身份認證,但是不是自己編寫完整的代碼來實現(xiàn)它,而是讓 Flask-HTTPAuth 擴展來為我們做。

使用 Flask-HTTPAuth,通過添加 login_required 裝飾器可以要求相應(yīng)的路由必須進行認證:

image.png

但是,F(xiàn)lask-HTTPAuth 需要給予更多的信息來驗證用戶的認證,當(dāng)然 Flask-HTTPAuth 有著許多的選項,它取決于應(yīng)用程序?qū)崿F(xiàn)的安全級別。

能夠提供最大自由度的選擇就是選用 verify_password 回調(diào)函數(shù),這個回調(diào)函數(shù)將會根據(jù)提供的 username 和 password 的組合的,返回 True(通過驗證) 或者 Flase(未通過驗證)。Flask-HTTPAuth 將會在需要驗證 username 和 password 對的時候調(diào)用這個回調(diào)函數(shù)。

verify_password 回調(diào)函數(shù)的實現(xiàn)如下:

image.png

這里是用 curl 請求只允許注冊用戶獲取的保護資源:

image.png

如果登錄失敗的話,會得到下面的內(nèi)容:

image.png

基于令牌的認證
每次請求必須發(fā)送 username 和 password 是十分不方便,即使是通過安全的 HTTP 傳輸?shù)脑掃€是存在風(fēng)險,因為客戶端必須要存儲不加密的認證憑證,這樣才能在每次請求中發(fā)送。

一種基于之前解決方案的優(yōu)化就是使用令牌來驗證請求。

我們的想法是客戶端應(yīng)用程序使用認證憑證交換了認證令牌,接下來的請求只發(fā)送認證令牌。

令牌是具有有效時間,過了有效時間后,令牌變成無效,需要重新獲取新的令牌。令牌的潛在風(fēng)險在于生成令牌的算法比較弱,但是有效期較短可以減少風(fēng)險。

令牌的生成以及驗證將會被添加到 User 模型中,其具體實現(xiàn)如下:

image.png

generate_auth_token() 方法生成一個以用戶 id 值為值,’id’ 為關(guān)鍵字的字典的加密令牌。令牌中同時加入了一個過期時間,默認為十分鐘(600 秒)。

驗證令牌是在 verify_auth_token() 靜態(tài)方法中實現(xiàn)的。靜態(tài)方法被使用在這里,是因為一旦令牌被解碼了用戶才可得知。如果令牌被解碼了,相應(yīng)的用戶將會被查詢出來并且返回。

API 需要一個獲取令牌的新函數(shù),這樣客戶端才能申請到令牌:

image.png

注意:這個函數(shù)是使用了 auth.login_required 裝飾器,也就是說需要提供 username 和 password。

剩下來的就是決策客戶端怎樣在請求中包含這個令牌。

HTTP 基本認證方式不特別要求 usernames 和 passwords 用于認證,在 HTTP 頭中這兩個字段可以用于任何類型的認證信息?;诹钆频恼J證,令牌可以作為 username 字段,password 字段可以忽略。

這就意味著服務(wù)器需要同時處理 username 和 password 作為認證,以及令牌作為 username 的認證方式。verify_password 回調(diào)函數(shù)需要同時支持這兩種方式:

image.png

新版的 verify_password 回調(diào)函數(shù)會嘗試認證兩次。首先它會把 username 參數(shù)作為令牌進行認證。如果沒有驗證通過的話,就會像基于密碼認證的一樣,驗證 username 和 password。

如下的 curl 請求能夠獲取一個認證的令牌:

image.png

現(xiàn)在可以使用令牌獲取資源:

image.png

需要注意的是這里并沒有使用密碼。

OAuth 認證
當(dāng)我們討論 RESTful 認證的時候,OAuth 協(xié)議經(jīng)常被提及到。
那么什么是 OAuth?
OAuth 可以有很多的含義。最通常就是一個應(yīng)用程序允許其它應(yīng)用程序的用戶的接入或者使用服務(wù),但是用戶必須使用應(yīng)用程序提供的登錄憑證。我建議閱讀者可以瀏覽 OAuth 了解更多知識。

好了, 一點點的理解,希望可以幫到你!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第二部分 Blog例子 第八章 用戶驗證 大部分程序需要追蹤用戶身份。當(dāng)用戶連接到程序,通過一系列步驟使自己的身份...
    易木成華閱讀 1,412評論 0 4
  • 大多數(shù)程序都需要進行用戶跟蹤。用戶鏈接程序時需要進行身份認證,通過這一過程,讓程序知道自己的身份。程序知道用戶是誰...
    藕絲空間閱讀 1,096評論 0 0
  • 22年12月更新:個人網(wǎng)站關(guān)停,如果仍舊對舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,390評論 22 257
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評論 19 139
  • 一個現(xiàn)代 web 應(yīng)用程序需要做的最常見的事情就是處理用戶。擁有基本賬號功能的一個應(yīng)用程序需要處理很多的事情,像注...
    邪惡的Sheldon閱讀 532評論 0 0

友情鏈接更多精彩內(nèi)容