本文首發於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)複製代碼