搜索
查看: 47|回复: 0

[网站] Python web框架实现增加BasicAuth认证详解

[复制链接]
发表于 2023-5-8 21:53:36 | 显示全部楼层 |阅读模式
这篇文章主要为大家详细介绍了Python如何在web框架中实现增加BasicAuth认证,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下
% w3 P+ Y/ Q& k

) v' s! @; D( `6 y' s# P' r

. `9 J  _: }1 v- J5 }" U1 X* n
+
目录
/ n4 {3 h, I. T9 F

上一篇文章,我们已经为框架定义了【响应对象】,该框架不仅可以获取客户端上传的报文信息,还能生成一些简单信息,如自定义响应头等等。今天我们再次完善一下该框架,给框架增加权限验证的功能,给框架加上一个BasicAuth的方法。

本篇文章所依赖的环境为:


8 e2 M1 h7 L7 l! v3 ~2 a$ v                               
登录/注册后可看大图

本次代码已经放到了gitee上:gitee.com/pdudo/golearn/tree/master/python/webFramework

  A% w: h$ p* J; q/ R
什么是http BashAuth

在日常生活或者工作中,你是否见到过这样的页面呢?


7 E7 |% y9 _8 Q* w                               
登录/注册后可看大图

当我们打开窗口,网页并不是里面加载出来的,而是弹出了一个输入框,让我们输入其用户名和密码,输入后待服务器验证通过后,才开始展现实际的网页内容。这个就是BashAuth了,全称为: Basic access authentication,也称基本认证。是一种极其简单http协议身份验证方式。BashAuth认证的方式是通过请求头来发送和校验的,而非我们熟知的cookie、token等。

还有一点需要注意,这里所展现的输入框,其实是浏览器底层拆解协议所支持的。

8 v" o% G- ~5 ^+ o0 Z/ X" m$ a, e: n
BasicAuth认证底层原理

BasicAuth使用的http协议进行身份验证的,所以会将身份信息携带在请求头中进行传输。

第一步: 用户在第一次进行浏览器请求页面的时候,不会携带认证信息,此时服务器接接收信息后,判断报文中请求头没有WWW-Authenticate,此时会返回客户端报文,其中需要将报文响应状态码为401,响应头新增一个key为WWW-Authenticate,值为realm加上请求域,做法是为了避免和其他URL相冲突。所以响应核心报文为:

HTTP/1.0 401 Unauthorized8 P5 `% Z+ m& F8 Q
WWW-Authenticate: Basic realm="pdudo sites"

其中状态码为401代表客户端错误,指的是需要身份验证,WWW-Authenticate响应头的值为Basic realm="pdudo sites",Basic代表验证的模式,realm代表请求域,请求域是为了和其他URL相冲突。

第二步: 当浏览器接收到该报文后,会判断其状态码为401并且请求头中有key为WWW-Authenticate,此时便会弹出输入框,让用户输入信息以便服务器校验。


+ t5 ~0 D5 g* @0 U" l) o
2 o% \- O9 m& |  e9 {* \! ^. Q

输入之后,不是直接发送给服务器,而是会根据服务器发送的验证模式进行校验,如basic,加入客户端发送的报文如下:

GET /index HTTP/1.1
3 o4 B- x0 B( U0 i# AHTTP_AUTHORIZATION: Basic cGR1ZG86anVlamlu

其中Get代表请求方式,/index表示请求路径,HTTP/1.1是http的版本。请求头HTTP_AUTHORIZATION表示验证数据,Basic是验证方式,cGR1ZG86anVlamlu表示用户名:密码,只不过浏览器使用base64进行编码了而已。

第三步: 服务器在接收到报文后,发现有HTTP_AUTHORIZATION,则会使用base64解码,发现客户端上传的数据为pdudo:juejin,以:为分割,前者是用户名,后则是密码。当验证通过后,进行发送其他信息,若验证未通过,则重复第一步。

+ q% u& y- X+ G


; L1 |+ w% p% w6 y; c% o                               
登录/注册后可看大图

将BasicAuth认证添加到框架中

我们已经知晓了BasicAuth认证的底层原理,所以可以开始修改我们的框架了,我们将其代码写到上一篇所述的response类中,代码如下:


/ ?  u6 C* B, M7 A3 {2 l[size=1em]
  1. def basicAuth(self):
    * u$ B2 e3 |/ r. Q
  2.     if "HTTP_AUTHORIZATION" not in self.response:
    " o6 }. B$ s: |( k1 T& V
  3.         return None,None,"HTTP_AUTHORIZATION request header not found"6 ~( b+ b8 A8 Z- M; }6 K
  4.     else:7 B% n7 L7 [& @' y% j" @8 J
  5.         originalVal = self.response["HTTP_AUTHORIZATION"]
    : J( X( y' M* m6 H
  6.         types = originalVal.split(" ")[0]& `7 \; Z# M3 ]  |9 a
  7.         values = originalVal.split(" ")[1]! a1 ?1 \2 [. S' d  U0 ~% k
  8.         if types == "Basic":
    # a2 R: B: A7 F1 X7 E& t8 U# x, P$ q
  9.             userAndPasswd = base64.b64decode(values).decode()# u( E( E3 }9 y0 }9 R  J6 d
  10.             user = userAndPasswd.split(":")[0]; J9 J# R0 @3 M/ ^: K" p
  11.             passwd = userAndPasswd.split(":")[1]
    3 B/ p7 u/ Q% T1 t. F: O/ a
  12.             return user,passwd,None
    ( C0 U5 j7 j) ]7 m; i
  13.         else:2 B, N/ x; w" H' ^! Z7 D3 O
  14.             return None, None, "HTTP_AUTHORIZATION request error,unrecognized type: %s " %(types)
复制代码

$ R$ r0 L8 ?8 v* j! a/ p# \

& P9 p2 b* X% H* l  {5 x* J[size=1em]

当客户端函数调用basicAuth时,服务器检查客户端http报文中,是否有HTTP_AUTHORIZATION,如果没有,则直接返回HTTP_AUTHORIZATION request header not found。

若请求头有该key,则将其抓出来存储到originalVal中,它的值类似于: Basic cGR1ZG86anVlamlu,前者是认证类型,后者是加密后字符串,所以我们需要分开将其取出来,存到types和values中,再判断types是否是Basic,如果是我们使用base64进行解密,解密后的值类似于pdudo:juejin,以冒号(:)隔开,前者为用户名,后者为密码,所以我们需要将字符串按照:进行拆分,前者保存到user中,后者保存到passwd中,最后将其数据给函数。


" X9 R$ r$ Z& A( N2 g- S

  N; f' s; H. G9 E

那当第一步检查请求头没有HTTP_AUTHORIZATION或者用户名密码不对,应该如何返回呢? 这个需要用户在函数中进行调用即可,例如:


. K) l5 y4 \6 g! |[size=1em]
  1. @myWeb.routes(path="/index",methods="all",regular=False)8 R, _3 _& f) g" G
  2. def index(r):
    2 n8 d! ~# T. }6 r/ d$ g
  3.     username, password , isok = r.basicAuth()
    2 G! m! ~# I0 I- V& q, K  t
  4.     if isok != None or username != "pdudo" or password != "juejin":3 _8 b7 {' _9 f+ }3 G# x, t3 C8 c) A
  5.         r.set_headers("WWW-Authenticate","Basic realm="pdudo sites"")# V$ A/ E  [/ l) h# g; F- k1 p9 o
  6.         r.status_code(401)6 }: ^1 |' V, C  W9 y7 m+ A
  7.         return
    8 {) i. F9 I0 Y, ?0 |
  8.     return "123"
复制代码
3 {/ P3 l1 w" o; f
  K5 _' \. ]& s
[size=1em]

上述代码,使用我们自己编写的myWeb框架,定义了一个路由/index,其方法为Get或者Post,regular=False则不使用正则路由,在函数中,通过r.basicAuth()来获取客户端上传的用户名密码,当用户名不等于pdudo或者密码不等于juejin或者解析失败的时候,会将响应状态码定义为401,并且设置响应头,key为WWW-Authenticate,值为Basic realm="pdudo sites"。


- i- s7 |/ h9 X# P框架功能测试

这里就不贴myWeb.py的代码了,太长了,大家可以去gitee上看,这里贴一下main.py代码:

  1. import myweb
    ' F' C5 Q/ n7 \5 D, x
  2. 2 @- }) a3 K5 L( j
  3. @myweb.routes(path="/index",methods="all",regular=False)
    " E2 `0 N3 D1 a& {2 ^
  4. , v# A' |4 p( ?) }" ~2 R
  5. def index(r):. h' B1 y/ m7 f/ f) q
  6.     username,password,isok = r.basicAuth()
    : g1 C5 Z/ }) K
  7.     print("username:",username,"passwd:",password)+ t" D/ M9 N% \! Q4 X5 m. r/ b" E
  8.     if isok != None or username != "pdudo" or password !="juejin":
    % \. W& X% W9 n; m# O: L+ e, w
  9.         r.set_headers("WWW-Authenticate","Basic realm="pdudo sites"")) ]8 V1 n" U. P3 `* V  @
  10.         r.status_code(401)  |1 R' y0 s6 F* w. f
  11.         return: {+ q* N( G3 r8 y$ w0 v# w
  12.      
    9 N3 V; x8 i) c8 C& e, j0 J
  13.      return "123"% U4 a+ s. q% Q9 `
  14. , \6 {. Z7 D1 h! r
  15. def main():
    3 ^& s! S: w2 H- `2 a2 E
  16.     myweb.run("",8888)
    $ I( P( V4 H* f# j' Q/ K

  17. - g3 ~  b- m. ^4 l. M5 Z
  18. if __name__ == '__main__':
    " [" g1 ^7 }7 |" y9 H8 l
  19.     main()
复制代码
. ~/ |" g7 J( o4 m

为了方便,我将每次获取到的数据,都打印一下,方便待会查看数据。

执行代码后,打开浏览器输入http://pdudo.juejin.cn:8888/index,当弹出框后,我们第一个故意输错,第二次才输正确:


; q, e2 }% U& L3 w+ g: P, p6 ^                               
登录/注册后可看大图

我们查看服务器日志,如下:


4 |9 r: E: b- Y2 u" N                               
登录/注册后可看大图

一共收到了3次,第一个输出后,并没有携带报文,被挡回来了,所以用户名和密码都为None,第二次则是密码输入不正确被挡回来了,第三次输入正确,成功得到数据123。


# H2 P( b" K9 @5 l4 e- N总结

本篇文章,我们介绍了一个极其古老的认证方式: BashAuth, 它是通过请求头来发送数据和验证的。接着我们了解了一下其认证过程,其中最常用的是类型是Basic,它表示将数据进行base64编码后传输,注意是编码,不是加密。所以在使用该功能的时候,最好配合https使用,以便被抓包后破解。 最后将其添加到我们的web框架myWeb.py中。

到此这篇关于Python web框架实现增加BasicAuth认证详解的文章就介绍到这了。


( g+ p! a! H' ~5 R. u# P3 S4 G) U. K! ~- x/ N
+ R9 i# B2 D" ^5 `8 Q- U

: P4 v, [) j2 }$ X# A6 U) I# T) h+ X; X* O% ]+ \
; l+ \3 _1 ]" m) P' b
$ {6 X. R; w* _; P+ s/ ~
4 J) I/ v$ A/ b
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

热议作品
精华帖子排行
精彩推荐

虾皮社区,成立十年了!

站长自己也搞不懂想做个什么,反正就是一直在努力的做!

Copyright © 2007-2019 xp6.org Powered by Discuz

QQ|小黑屋|手机版|Archiver|虾皮社区 ( 鲁ICP备13006813号-1 ) 鲁公网安备 37021102000261号 |网站地图
返回顶部 返回列表