Python?web框架實(shí)現(xiàn)增加BasicAuth認(rèn)證詳解
上一篇文章,我們已經(jīng)為框架定義了【響應(yīng)對(duì)象】,該框架不僅可以獲取客戶端上傳的報(bào)文信息,還能生成一些簡(jiǎn)單信息,如自定義響應(yīng)頭等等。今天我們?cè)俅瓮晟埔幌略摽蚣埽o框架增加權(quán)限驗(yàn)證的功能,給框架加上一個(gè)BasicAuth的方法。
本篇文章所依賴的環(huán)境為:

本次代碼已經(jīng)放到了gitee上:gitee.com/pdudo/golearn/tree/master/python/webFramework
什么是http BashAuth
在日常生活或者工作中,你是否見(jiàn)到過(guò)這樣的頁(yè)面呢?

當(dāng)我們打開(kāi)窗口,網(wǎng)頁(yè)并不是里面加載出來(lái)的,而是彈出了一個(gè)輸入框,讓我們輸入其用戶名和密碼,輸入后待服務(wù)器驗(yàn)證通過(guò)后,才開(kāi)始展現(xiàn)實(shí)際的網(wǎng)頁(yè)內(nèi)容。這個(gè)就是BashAuth了,全稱為: Basic access authentication,也稱基本認(rèn)證。是一種極其簡(jiǎn)單http協(xié)議身份驗(yàn)證方式。BashAuth認(rèn)證的方式是通過(guò)請(qǐng)求頭來(lái)發(fā)送和校驗(yàn)的,而非我們熟知的cookie、token等。
還有一點(diǎn)需要注意,這里所展現(xiàn)的輸入框,其實(shí)是瀏覽器底層拆解協(xié)議所支持的。
BasicAuth認(rèn)證底層原理
BasicAuth使用的http協(xié)議進(jìn)行身份驗(yàn)證的,所以會(huì)將身份信息攜帶在請(qǐng)求頭中進(jìn)行傳輸。
第一步: 用戶在第一次進(jìn)行瀏覽器請(qǐng)求頁(yè)面的時(shí)候,不會(huì)攜帶認(rèn)證信息,此時(shí)服務(wù)器接接收信息后,判斷報(bào)文中請(qǐng)求頭沒(méi)有WWW-Authenticate,此時(shí)會(huì)返回客戶端報(bào)文,其中需要將報(bào)文響應(yīng)狀態(tài)碼為401,響應(yīng)頭新增一個(gè)key為WWW-Authenticate,值為realm加上請(qǐng)求域,做法是為了避免和其他URL相沖突。所以響應(yīng)核心報(bào)文為:
HTTP/1.0 401 Unauthorized
WWW-Authenticate: Basic realm="pdudo sites"
其中狀態(tài)碼為401代表客戶端錯(cuò)誤,指的是需要身份驗(yàn)證,WWW-Authenticate響應(yīng)頭的值為Basic realm="pdudo sites",Basic代表驗(yàn)證的模式,realm代表請(qǐng)求域,請(qǐng)求域是為了和其他URL相沖突。
第二步: 當(dāng)瀏覽器接收到該報(bào)文后,會(huì)判斷其狀態(tài)碼為401并且請(qǐng)求頭中有key為WWW-Authenticate,此時(shí)便會(huì)彈出輸入框,讓用戶輸入信息以便服務(wù)器校驗(yàn)。
輸入之后,不是直接發(fā)送給服務(wù)器,而是會(huì)根據(jù)服務(wù)器發(fā)送的驗(yàn)證模式進(jìn)行校驗(yàn),如basic,加入客戶端發(fā)送的報(bào)文如下:
GET /index HTTP/1.1
HTTP_AUTHORIZATION: Basic cGR1ZG86anVlamlu
其中Get代表請(qǐng)求方式,/index表示請(qǐng)求路徑,HTTP/1.1是http的版本。請(qǐng)求頭HTTP_AUTHORIZATION表示驗(yàn)證數(shù)據(jù),Basic是驗(yàn)證方式,cGR1ZG86anVlamlu表示用戶名:密碼,只不過(guò)瀏覽器使用base64進(jìn)行編碼了而已。
第三步: 服務(wù)器在接收到報(bào)文后,發(fā)現(xiàn)有HTTP_AUTHORIZATION,則會(huì)使用base64解碼,發(fā)現(xiàn)客戶端上傳的數(shù)據(jù)為pdudo:juejin,以:為分割,前者是用戶名,后則是密碼。當(dāng)驗(yàn)證通過(guò)后,進(jìn)行發(fā)送其他信息,若驗(yàn)證未通過(guò),則重復(fù)第一步。
將BasicAuth認(rèn)證添加到框架中
我們已經(jīng)知曉了BasicAuth認(rèn)證的底層原理,所以可以開(kāi)始修改我們的框架了,我們將其代碼寫(xiě)到上一篇所述的response類中,代碼如下:
def basicAuth(self):
if "HTTP_AUTHORIZATION" not in self.response:
return None,None,"HTTP_AUTHORIZATION request header not found"
else:
originalVal = self.response["HTTP_AUTHORIZATION"]
types = originalVal.split(" ")[0]
values = originalVal.split(" ")[1]
if types == "Basic":
userAndPasswd = base64.b64decode(values).decode()
user = userAndPasswd.split(":")[0]
passwd = userAndPasswd.split(":")[1]
return user,passwd,None
else:
return None, None, "HTTP_AUTHORIZATION request error,unrecognized type: %s " %(types)當(dāng)客戶端函數(shù)調(diào)用basicAuth時(shí),服務(wù)器檢查客戶端http報(bào)文中,是否有HTTP_AUTHORIZATION,如果沒(méi)有,則直接返回HTTP_AUTHORIZATION request header not found。
若請(qǐng)求頭有該key,則將其抓出來(lái)存儲(chǔ)到originalVal中,它的值類似于: Basic cGR1ZG86anVlamlu,前者是認(rèn)證類型,后者是加密后字符串,所以我們需要分開(kāi)將其取出來(lái),存到types和values中,再判斷types是否是Basic,如果是我們使用base64進(jìn)行解密,解密后的值類似于pdudo:juejin,以冒號(hào)(:)隔開(kāi),前者為用戶名,后者為密碼,所以我們需要將字符串按照:進(jìn)行拆分,前者保存到user中,后者保存到passwd中,最后將其數(shù)據(jù)給函數(shù)。
那當(dāng)?shù)谝徊綑z查請(qǐng)求頭沒(méi)有HTTP_AUTHORIZATION或者用戶名密碼不對(duì),應(yīng)該如何返回呢? 這個(gè)需要用戶在函數(shù)中進(jìn)行調(diào)用即可,例如:
@myWeb.routes(path="/index",methods="all",regular=False)
def index(r):
username, password , isok = r.basicAuth()
if isok != None or username != "pdudo" or password != "juejin":
r.set_headers("WWW-Authenticate","Basic realm="pdudo sites"")
r.status_code(401)
return
return "123"上述代碼,使用我們自己編寫(xiě)的myWeb框架,定義了一個(gè)路由/index,其方法為Get或者Post,regular=False則不使用正則路由,在函數(shù)中,通過(guò)r.basicAuth()來(lái)獲取客戶端上傳的用戶名密碼,當(dāng)用戶名不等于pdudo或者密碼不等于juejin或者解析失敗的時(shí)候,會(huì)將響應(yīng)狀態(tài)碼定義為401,并且設(shè)置響應(yīng)頭,key為WWW-Authenticate,值為Basic realm="pdudo sites"。
框架功能測(cè)試
這里就不貼myWeb.py的代碼了,太長(zhǎng)了,大家可以去gitee上看,這里貼一下main.py代碼:
import myweb
@myweb.routes(path="/index",methods="all",regular=False)
def index(r):
username,password,isok = r.basicAuth()
print("username:",username,"passwd:",password)
if isok != None or username != "pdudo" or password !="juejin":
r.set_headers("WWW-Authenticate","Basic realm=\"pdudo sites\"")
r.status_code(401)
return
return "123"
def main():
myweb.run("",8888)
if __name__ == '__main__':
main()為了方便,我將每次獲取到的數(shù)據(jù),都打印一下,方便待會(huì)查看數(shù)據(jù)。
執(zhí)行代碼后,打開(kāi)瀏覽器輸入http://pdudo.juejin.cn:8888/index,當(dāng)彈出框后,我們第一個(gè)故意輸錯(cuò),第二次才輸正確:

我們查看服務(wù)器日志,如下:

一共收到了3次,第一個(gè)輸出后,并沒(méi)有攜帶報(bào)文,被擋回來(lái)了,所以用戶名和密碼都為None,第二次則是密碼輸入不正確被擋回來(lái)了,第三次輸入正確,成功得到數(shù)據(jù)123。
總結(jié)
本篇文章,我們介紹了一個(gè)極其古老的認(rèn)證方式: BashAuth, 它是通過(guò)請(qǐng)求頭來(lái)發(fā)送數(shù)據(jù)和驗(yàn)證的。接著我們了解了一下其認(rèn)證過(guò)程,其中最常用的是類型是Basic,它表示將數(shù)據(jù)進(jìn)行base64編碼后傳輸,注意是編碼,不是加密。所以在使用該功能的時(shí)候,最好配合https使用,以便被抓包后破解。 最后將其添加到我們的web框架myWeb.py中。
到此這篇關(guān)于Python web框架實(shí)現(xiàn)增加BasicAuth認(rèn)證詳解的文章就介紹到這了,更多相關(guān)Python增加BasicAuth認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于python解析XML文件并將數(shù)據(jù)存儲(chǔ)到MongoDB的代碼示例
在軟件開(kāi)發(fā)中,我們經(jīng)常需要處理各種格式的數(shù)據(jù),XML 是一種常用的數(shù)據(jù)交換格式,它可以存儲(chǔ)和傳輸結(jié)構(gòu)化數(shù)據(jù),很多網(wǎng)站會(huì)提供 XML 格式的數(shù)據(jù)接口,以便其他系統(tǒng)可以方便地獲取數(shù)據(jù),本文介紹了基于python解析XML文件并將數(shù)據(jù)存儲(chǔ)到MongoDB的代碼示例,需要的朋友可以參考下2024-06-06
用Python編寫(xiě)一個(gè)鼠標(biāo)自動(dòng)點(diǎn)擊程序詳細(xì)過(guò)程
這篇文章主要給大家介紹了關(guān)于如何使用Python編寫(xiě)一個(gè)鼠標(biāo)自動(dòng)點(diǎn)擊程序,通過(guò)使用pyautogui庫(kù),可以實(shí)現(xiàn)模擬鼠標(biāo)點(diǎn)擊的功能,文章還介紹了如何使用time庫(kù)和threading庫(kù)來(lái)控制點(diǎn)擊間隔時(shí)間和實(shí)現(xiàn)多線程,需要的朋友可以參考下2024-11-11
python GUI庫(kù)圖形界面開(kāi)發(fā)之PyQt5 UI主線程與耗時(shí)線程分離詳細(xì)方法實(shí)例
這篇文章主要介紹了python GUI庫(kù)圖形界面開(kāi)發(fā)之PyQt5 UI主線程與耗時(shí)線程分離詳細(xì)方法實(shí)例,需要的朋友可以參考下2020-02-02
python+tkinter實(shí)現(xiàn)學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了python+tkinter實(shí)現(xiàn)學(xué)生管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08
python自動(dòng)化工具日志查詢分析腳本代碼實(shí)現(xiàn)
這篇文章主要介紹了python日志查詢分析腳本代碼的實(shí)現(xiàn),分為受控節(jié)點(diǎn)和主控節(jié)點(diǎn),大家參考使用吧2013-11-11
Python中函數(shù)及默認(rèn)參數(shù)的定義與調(diào)用操作實(shí)例分析
這篇文章主要介紹了Python中函數(shù)及默認(rèn)參數(shù)的定義與調(diào)用操作,結(jié)合實(shí)例形式分析了Python中函數(shù)的定義及參數(shù)的使用技巧,需要的朋友可以參考下2017-07-07
Python MNIST手寫(xiě)體識(shí)別詳解與試練
MNIST(官方網(wǎng)站)是非常有名的手寫(xiě)體數(shù)字識(shí)別數(shù)據(jù)集,在Tensorflow的官方網(wǎng)站里,第一個(gè)就拿它來(lái)做實(shí)戰(zhàn)講解,咱們也以此作為開(kāi)始的項(xiàng)目2021-11-11
安裝pyhttpx解決ImportError: DLL load failed錯(cuò)誤
這篇文章主要為大家介紹了安裝pyhttpx解決ImportError: DLL load failed錯(cuò)誤,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
Tensorflow實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)用于人臉關(guān)鍵點(diǎn)識(shí)別
這篇文章主要介紹了Tensorflow實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)用于人臉關(guān)鍵點(diǎn)識(shí)別,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03

