flask-httpauth
flask-httpauth
1. flask-httpauth
文档:https://flask-httpauth.readthedocs.io/en/latest/
1.1. 安装
pip install flask-httpauth
2. 简介
它有三种认证方式:
- 基本认证(Basic Authentication)
- 摘要认证(Digest Authentication)
- 标志认证(Token Authentication)。
2.1. HTTPBasicAuth
class flask_httpauth.HTTPBasicAuth
This class handles HTTP Basic authentication for Flask routes.
init(scheme=None, realm=None)
If the optional scheme argument is provided, it will be used instead of the standard “Basic” scheme in the WWW-Authenticate response.(不太明白什么意思。)
verify_password(verify_password_callback)
模块还有get_password,hash_password等类似方法,但功能有一些重复,一般使用此方法即可。
它返回True或有效对象即可通过验证。
返回False无法验证失败。
@auth.verify_password
def verify_pw(username, password):
return call_custom_verify_function(username, password)
login_required(view_function_callback)
This callback function will be called when authentication is successful. This will typically be a Flask view function. Example:
@app.route('/private')
@auth.login_required
def private_page():
return "Only for authorized people!"
2.2. HTTPDigestAuth
class flask_httpauth.HTTPDigestAuth
2.3. HTTPTokenAuth
class flask_httpauth.HTTPTokenAuth
同HTTPBasicAuth类似,它也提供”login_required”装饰器来认证视图函数,”error_handler”装饰器来处理错误。区别是,它没有”verify_password”装饰器,相应的,它提供了”verify_token”装饰器来验证令牌。我们来看下代码,为了简化,我们将Token与用户的关系保存在一个字典中:
verify_token(verify_token_callback)
在使用此类做为验证时,必需实现此方法。
@auth.verify_token
def verify_token(token):
return User.query.filter_by(token=token).first()
2.4. MultiAuth
Flask-HTTPAuth扩展还支持几种不同认证的组合,比如上面我们介绍了HTTPBasicAuth和HTTPTokenAuth,我们可以将两者组合在一起,其中任意一个认证通过,即可以访问应用视图。实现起来也很简单,只需将不同的认证实例化为不同的对象,并将其传入MultiAuth对象即可。大体代码如下:
auth_basic = flask_httpauth.HTTPBasicAuth()
auth_token = flask_httpauth.HTTPTokenAuth(scheme='SWT')
auth_multi = flask_httpauth.MultiAuth(auth_basic, auth_token)
@blue_restful.route('/1')
@auth_token.login_required
def restful_index():
return 'restful api1.'
这里,每个认证都有自己的验证和错误处理函数,不过在视图上,我们使用”@multi_auth.login_required”来实现多重认证
2.5. 错误处理
在之前的例子中,如果未认证成功,服务端会返回401状态码及”Unauthorized Access”文本信息。你可以重写错误处理方法,并用”@auth.error_handler”装饰器来修饰它:
from flask import make_response, jsonify
@auth.error_handler
def unauthorized():
return make_response(jsonify({'error': 'Unauthorized access'}), 401)
有了上面的”unauthorized()”方法后,如果认证未成功,服务端返回401状态码,并返回JSON信息”{‘error’: ‘Unauthorized access’}”。
3. 实战
新建auth_verify.py
from flask import g
import flask_httpauth
from itsdangerous import TimedJSONWebSignatureSerializer, BadSignature, SignatureExpired
from config import Config
auth_basic = flask_httpauth.HTTPBasicAuth()
auth_token = flask_httpauth.HTTPTokenAuth(scheme="JWT")
auth_multi = flask_httpauth.MultiAuth(auth_basic, auth_token)
TOKENS = {
"token1": 't1',
"token2": 't2',
"token3": "t3"
}
@auth_basic.verify_password
def verify_password(user, password):
print("verify_password", user, password)
if not password:
return False
return user
@auth_token.verify_token
def verify_token(token):
g.user = None
token = token_s.loads(token, 'salt')
print('verify token:', token)
if token['id'] in TOKENS:
g.user = TOKENS[token['id']]
return True
return False
# 创建token
token_s = TimedJSONWebSignatureSerializer(Config.SECRET_KEY, Config.TOKEN_EXPIRATION)
def create_token(id):
token = token_s.dumps({'id':id}, 'salt')
return token.decode('ascii')
说明:
- auth_token = flask_httpauth.HTTPTokenAuth(scheme="JWT")中的scheme是一个前缀,用于在请求中构建头部参数;
- token = token_s.dumps({'id':id}, 'salt') salt是hash的加盐,在loads时也要相应设置,否则解密错误;
视图方法
# flask restful
from flask_restful import Resource, Api, reqparse
parser = reqparse.RequestParser()
parser.add_argument('task', type=str, help='task')
parser.add_argument('pwd', type=str, help='task')
parser.add_argument("limit", type=int, required=False)
parser.add_argument("offset", type=int, required=False)
parser.add_argument("sortby", type=str, required=False)
TODO_TASKS = { 'todo1': {'task': 'build an API'},
'todo2': {'task': '?????'},
'todo3': {'task': 'profit!'},
}
def dect(f):
def _inner(*ar, **kw):
print('fffff', f, ar, kw)
return f(ar, kw)
return _inner
class FlaskRestful_API(Resource):
# 添加认证
method_decorators = [auth_token.login_required]
def get(self, id=None, name=None):
"""
获取数据
:param id:
:param name:
:return:
"""
args = parser.parse_args()
print('ar', args)
if not id:
return TODO_TASKS
else:
task = TODO_TASKS.get(str(id), None)
return task
def put(self, id):
args = parser.parse_args()
print(args)
print(request.form)
print('put', request.form)
if id in TODO_TASKS:
TODO_TASKS[id].update(request.form)
return TODO_TASKS[id]
else:
abort(404)
def post(self):
args = parser.parse_args()
print(args)
print(request.form)
res_json = jsonify({
'method': request.method
, 'url': request.url
, 'values': request.values
, 'headers': dict(request.headers)
, 'cookie': request.cookies
, 'session': request.host
, 'body': request.data.decode()
, 'origi': request.remote_addr
, "endpoint": request.endpoint
})
return res_json
def delete(self):
pass
# 定义api类并注册视图
api = Api(blue_restful)
# 注册视图
# 注意endpoint,如果不指定便为类名的小写
api.add_resource(FlaskRestful_API, '/rest/', '/rest/', endpoint="rest_api")
# 返回token
from app.auth_verify import create_token
@blue_restful.route('/login', methods=["POST"])
def login():
"""接受参数,返回token"""
# print(request.headers)
# user = request.json['username']
# pssword = request.json['password']
token = create_token('token2')
return jsonify({'code': 1, 'msg':'成功', 'data': token})
说明:
- login视图用于获取token,使用post是为了加密;
模拟请求
使用requests模拟请求
def _test_func():
data = {'username':'name', 'password': 'pass'}
res = requests.post("http://127.0.0.1:9000/restful/login", headers={"Accept":"application/json"})
print('res.json', res.json())
print(res.headers)
token = res.json()['data']
print("token:", token)
headers = {"Authorization": "JWT "+ token, "Authenticate":'Bearer realm="owejoiod"'}
print(headers)
res = requests.get("http://127.0.0.1:9000/restful/rest/todo1", headers=headers)
print(res)
print(res.headers, res.text)
说明:
- 第一次post是为了获取token;
- 请求传递token需要设置headers.Authorization,这里的“JWT ”就是在实例化HTTPTokenAuth(scheme="JWT")时所附加的前缀“JWT ”。

浙公网安备 33010602011771号