视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Python使用htpasswd实现基本认证授权的例子
2020-11-27 14:30:31 责编:小采
文档


前面我讲解了如何将树莓派(Raspberry Pi)打造成无线路由,感觉每次通过命令ssh管理显麻烦,于是自己动手编写Web界面,主要是使用Python编写的CGI程序,这里用到了mini_httpd这款轻量的Web服务器,本来想装nginx的,但是想想还是精简一些吧,毕竟资源有限,况且Web管理界面仅我一个人访问。

CGI应用跑起来了,但问题来了,如何实现普通路由的那种打开页面就弹出输入用户名密码的对话框?

这里主要用到HTTP协议的一个知识,那就是HTTP基本认证。

服务器端通过发送类似下面的头信息来实现需要认证请求:
代码如下:


HTTP/1.0 401 Authorization Required
WWW-Authenticate: Basic realm="Secure Area"
Content-Type: text/html


针对上述要求,于是我在CGI中采用了如下的Python代码:
代码如下:


def check_login():
import base

if "Authorization" in os.environ:
try:
cred = base.bdecode(os.environ['Authorization'].split(' ')[1])
username, password = cred.split(":")
if db_validate_user(username, password): # 这里匹配数据库用户名密码
return True
except:
pass

print 'Status: 401 Unauthorized'
print 'Pragma: no-cache'
print 'Content-Type: text/html'
print 'WWW-Authenticate: Basic realm=\"My Wireless Router\"'
print
print """


Not authenticated


Not authenticated.



"""
return False

# 调用
if not check_login():
sys.exit(0)


但是实际操作下来后发现mini_httpd并不转发来自用户的Authorization的用户名和密码,也就是说os.environ取不到这个头信息,从而导致认证失败。

经过网上搜索后得知mini_httpd原生支持通过.htpasswd实现简单认证的技术,也就是说我们可以在需要授权访问的目录下建立.htpasswd文件实现,当然这个文件是有格式要求的,我们可以通过htpasswd命令来创建。这个命令一般Apache服务器软件会自带,不过mini_httpd也自带了,所以你可以直接使用这个命令。
代码如下:


# 建立文件名 账户名 密码
htpasswd -bc .htpasswd admin 123456


当一个目录下有.htpasswd文件时,mini_httpd就会弹出要求用户名和密码的对话框,输入正确后才可以浏览,如果没有这个文件则正常浏览。

因为我的cgi应用是基于Python的,所以我希望Python能够管理.htpasswd文件,幸好Python世界里有现成的库,避免了我们重复造轮子,使用easy_install的安装方式如下:
代码如下:


sudo easy_install htpasswd


官方文档给出的例子如下,感觉操作挺方便的,大家可以试一试:
代码如下:


import htpasswd

with htpasswd.Basic("/path/to/user.db") as userdb:

try:
userdb.add("bob", "password")
except htpasswd.basic.UserExists, e:
print e
try:
userdb.change_password("alice", "newpassword")
except htpasswd.basic.UserNotExists, e:
print e

with htpasswd.Group("/path/to/group.db") as groupdb:

try:
groupdb.add_user("bob", "admins")
except htpasswd.group.UserAlreadyInAGroup, e:
print e
try:
groupdb.delete_user("alice", "managers")
except htpasswd.group.UserNotInAGroup, e:
print e

下载本文
显示全文
专题