一種非常常見的設(shè)置是將用戶信息(用戶名、密碼、角色等)存儲在數(shù)據(jù)庫中。現(xiàn)在,假設(shè)我們要創(chuàng)建一個訪問令牌,其中令牌標(biāo)識是用戶名,我們還希望將用戶角色作為附加聲明存儲在令牌中。我們可以使用上一節(jié)討論的user_claims_loader()裝飾器來實現(xiàn)這一點。
但是,如果我們將用戶名傳遞給`user_claims_loader()`,我們最終需要從數(shù)據(jù)庫查詢該用戶兩次。
* 1 第一次是當(dāng)?shù)卿浂它c被點擊時,我們需要驗證用戶名和密碼。
* 2 第二次是在`user_claims_loader()`函數(shù)中,因為我們需要查詢這個用戶的角色。這不是什么大事,但顯然它可以更有效率。
在本章的方法中,提供了將任何對象傳遞給create_access_token()函數(shù)的能力,然后將該函數(shù)作為user_claims_loader()傳遞。這允許我們只訪問數(shù)據(jù)庫一次,但是引入了一個需要解決的新問題。我們?nèi)匀恍枰獜膶ο笾刑崛∮脩裘?,這樣我們就可以讓用戶名作為新令牌的標(biāo)識。我們可以為此使用第二個裝飾器user_identity_loader(),它允許您接收傳入create_access_token()的任何對象,并從該對象返回一個json序列化的標(biāo)識。
請看示例代碼:
from flask import Flask, jsonify, request
from flask_jwt_extended import (
JWTManager, jwt_required, create_access_token,
get_jwt_identity, get_jwt_claims
)
app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = 'super-secret' # Change this!
jwt = JWTManager(app)
#創(chuàng)建一個用來構(gòu)建JWT數(shù)據(jù)的復(fù)雜對象
#看起來有點像SQLAlchemy 的實例
class UserObject:
def __init__(self, username, roles):
self.username = username
self.roles = roles
#定義jwt.user_claims_loader裝飾器,該裝飾器會在調(diào)用create_access_token函數(shù)時自動被調(diào)用,
#user_claims_loader的參數(shù)就是傳遞給 create_access_token的參數(shù)
#user_claims_loader返回的數(shù)據(jù)會被保存到j(luò)wt 中,作為claims存在
@jwt.user_claims_loader
def add_claims_to_access_token(user):
return {'roles': user.roles}
#user_identity_loader裝飾器,該裝飾器會在調(diào)用create_access_token函數(shù)時自動被調(diào)用,
#user_identity_loader的參數(shù)就是傳遞給 create_access_token的參數(shù)
#user_claims_loader返回的數(shù)據(jù)會被保存到j(luò)wt 中,作為identity存在
@jwt.user_identity_loader
def user_identity_lookup(user):
return user.username
@app.route('/login', methods=['POST'])
def login():
username = request.json.get('username', None)
password = request.json.get('password', None)
if username != 'test' or password != 'test':
return jsonify({"msg": "Bad username or password"}), 401
# Create an example UserObject
user = UserObject(username='test', roles=['foo', 'bar'])
# We can now pass this complex object directly to the
# create_access_token method. This will allow us to access
# the properties of this object in the user_claims_loader
# function, and get the identity of this object from the
# user_identity_loader function.
access_token = create_access_token(identity=user)
ret = {'access_token': access_token}
return jsonify(ret), 200
@app.route('/protected', methods=['GET'])
@jwt_required
def protected():
ret = {
'current_identity': get_jwt_identity(), # test
'current_roles': get_jwt_claims()['roles'] # ['foo', 'bar']
}
return jsonify(ret), 200
if __name__ == '__main__':
app.run()