本文首发于Gevin的博客python
原文连接:Flask Basic Auth的实现json
未经 Gevin 受权,禁止转载flask
RESTful API开发中,Authentication(认证)机制的实现一般『很是必要』。Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码便可,Basic Auth 经常使用于开发和测试阶段,Flask 做为一个微框架,虽然没有集成Basic Auth的实现,但相关信息均已提供,咱们只需作简单封装,便可实现Basic Auth。服务器
思路:利用request.authorization和装饰器restful
Basic Auth机制,客户端向服务器发请求时,会在请求的http header中提供用户名和密码做为认证信息,格式为"Authorization":'basic '+b64Val
,其中b64Val为通过base64转码后的用户名密码信息,即b64Val=base64.b64encode('username:password')
session
Flask 中,客户端的请求均由request
类处理,对于Basic Auth中的传来的用户名和密码,已经保存到request.authorization
中,即:框架
auth = request.authorization
username = auth.username
password = auth.password复制代码
所以,Flask中只要封装一个basic auth装饰器,而后把该装饰器应用到须要使用basic auth的API中便可:函数
def basic_auth_required(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
return not_authenticated()
return f(*args, **kwargs)
return decorated复制代码
其中,check_auth()
和not_authenticated()
函数实现以下:post
def check_auth(username, password):
"""This function is called to check if a username / password combination is valid. """
try:
user = models.User.objects.get(username=username)
except models.User.DoesNotExist:
user = None
if user and user.verify_password(password):
return True
return False
def not_authenticated():
"""Sends a 401 response that enables basic auth"""
return Response(
'Could not verify your access level for that URL.\n'
'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'})复制代码
API中使用该装饰器时,便可完成API的basic auth认证机制。对function view和class based view实现分别以下:测试
# function View
@basic_auth_required
def test_get_current_user():
return jsonify(username=current_user.username)
# Class Based View
class TestAPIView(MethodView):
decorators = [basic_auth_required, ]
def get(self):
data = {'a':1, 'b':2, 'c':3}
return jsonify(data)
def post(self):
data = request.get_json()
return jsonify(data)
def put(self):
data = request.get_json()
return jsonify(data)
def patch(self):
data = request.get_json()
return jsonify(data)复制代码
Flask-login中的current_user
是一个很是好用的对象,使业务逻辑与当前用户产生交集时,用户相关信息可以信手即来。在RESTful API开发中,不少API的业务逻辑也会与认证用户发生交集,若是current_user
依然有效,不少相关业务逻辑能够解耦,代码也会更加优雅。但Flask-login中,current_user
默认是基于session
的,API中不存在session
,current_user
没法使用。所幸强大的Flask-login 内置了request_loader
callback,容许经过header中的信息加载当前用户,方法以下:
@login_manager.request_loader
def load_user_from_request(request):
auth = request.authorization
if not auth:
return None
try:
user = User.objects.get(username=auth.username)
except User.DoesNotExist:
user = None
return user复制代码
把上面代码放到项目中,就能够在API的业务逻辑中把basic auth
和 current user
结合用起来,如:
@basic_auth_required
def test_get_current_user():
return jsonify(username=current_user.username)复制代码