python 笔记16--Flask-BasicAuth 使用与重构

1 介绍

Flask-BasicAuth 是一种Flask 扩展,它可以通过HTTP基础访问认证来保护部分视图或者全部应用。如下图,用户最开始访问应用的时候会弹出用户密码输入框,输入成功后才能访问应用。
默认情况下 Flask-BasicAuth 只支持单用户认证,而实际大部分应用是多用户认证,因此需要在其基础上加以调整。本文对 Flask-BasicAuth 原理进行介绍,并通过简单的案例重写其认证模块,实现一个简单的多用户登录功能。

python 笔记16--Flask-BasicAuth 使用与重构_python

2 方案

2.1 BasicAuth 使用与原理

flask BasicAuth 基础案例如下, 只需要引入 BasicAuth、配置 app.config、实例化BasicAuth,就可以使用BasicAuth了。
其中,app.config[‘BASIC_AUTH_FORCE’]为True 就默认对所有 api 进行认证, 如果设置为 False, 那么可以通过 @basic_auth.required 对指定 api 进行认证。

案例1: 对所有 api 进行认证

from flask import Flask
from flask_basicauth import BasicAuth

app = Flask(__name__)

app.config['BASIC_AUTH_USERNAME'] = 'admin'
app.config['BASIC_AUTH_PASSWORD'] = '123456'

app.config['BASIC_AUTH_FORCE'] = True
basic_auth = BasicAuth(app)


@app.route('/')
def hello_world(): # put application's code here
return 'Hello World!'


@app.route('/bye')
def bye():
return 'Good Bye!'


if __name__ == '__main__':
app.run()

案例2: 只对 /bye 进行认证

from flask import Flask
from flask_basicauth import BasicAuth

app = Flask(__name__)

app.config['BASIC_AUTH_USERNAME'] = 'admin'
app.config['BASIC_AUTH_PASSWORD'] = '123456'

app.config['BASIC_AUTH_FORCE'] = False
basic_auth = BasicAuth(app)


@app.route('/')
def hello_world(): # put application's code here
return 'Hello World!'


@app.route('/bye')
@basic_auth.required
def bye():
return 'Good Bye!'


if __name__ == '__main__':
app.run()

Flask-BasicAuth 核心源码:
Flask-BasicAuth 当前所有源码才60多行,下面贴出其主要部分;其中,init_app 中 require_basic_auth会判断 api 是否需要认证,若需要认证 check_credentials 就会将用户输入的账密信息和 app 默认的 BASIC_AUTH_USERNAME/BASIC_AUTH_PASSWORD 进行对比,通过即可正常返回数据。

# 默认路径 lib/python3.x/site-packages/flask_basicauth.py
class BasicAuth(object):
def __init__(self, app=None):
if app is not None:
self.app = app
self.init_app(app)
else:
self.app = None

def init_app(self, app):
app.config.setdefault('BASIC_AUTH_FORCE', False)
app.config.setdefault('BASIC_AUTH_REALM', '')

@app.before_request
def require_basic_auth():
if not current_app.config['BASIC_AUTH_FORCE']:
return
if not self.authenticate():
return self.challenge()

def check_credentials(self, username, password):
correct_username = current_app.config['BASIC_AUTH_USERNAME']
correct_password = current_app.config['BASIC_AUTH_PASSWORD']
return username == correct_username and password ==

2.2 BasicAuth 优化重构

上面已经提到了BasicAuth 通过默认账密和 check_credentials 来进行用户验证,因此只需要重写 check_credentials 功能就可以实现一个个性化的多账号认证功能。

重新的 new_basicauth:

vim new_basicauth.py
import base64
from functools import wraps

from flask import current_app, request, Response


__version__ = '0.2.0'


def check_user_password(username, password):
local_users = {
'admin': 'pass0',
'admin1': 'pass1',
'admin2': 'pass2'
}
if username in local_users.keys() and password == local_users[username]:
return True
else:
return False


class BasicAuth(object):
def __init__(self, app=None):
if app is not None:
self.app = app
self.init_app(app)
else:
self.app = None

def init_app(self, app):
app.config.setdefault('BASIC_AUTH_FORCE', False)
app.config.setdefault('BASIC_AUTH_REALM', '')

@app.before_request
def require_basic_auth():
if not current_app.config['BASIC_AUTH_FORCE']:
return
if not self.authenticate():
return self.challenge()

def check_credentials(self, username, password):
print(request.authorization)
return check_user_password(username, password)

def authenticate(self):
auth = request.authorization
return (
auth and auth.type == 'basic' and
self.check_credentials(auth.username, auth.password)
)

def challenge(self):
realm = current_app.config['BASIC_AUTH_REALM']
return Response(
status=401,
headers={'WWW-Authenticate': 'Basic realm="%s"' % realm}
)

def required(self, view_func):
@wraps(view_func)
def wrapper(*args, **kwargs):
if self.authenticate():
return view_func(*args, **kwargs)
else:
return self.challenge()
return

测试结果:

如下图, admin 和 admin1 都通过了, 即重写 check_credentials 后就支持多用户认证了。

python 笔记16--Flask-BasicAuth 使用与重构_flask身份验证_02

3 注意事项

  1. 本为了内容精简,直接在 check_user_password 中内置了几个用户模拟效果,实际中可以在 db 中查找用户是否存在, 也可以从 ldap 中查询。即可以按需对接其它账号系统或者 db,实现个性化的多用户认证。

4 说明

​flask-basicauth.readthedocs.io/en/latest​​​​Python编程:Flask-BasicAuth实现Authentication登录认证​