一種非常常見的設(shè)置是將用戶信息(用戶名续膳、密碼改艇、角色等)存儲(chǔ)在數(shù)據(jù)庫(kù)中。現(xiàn)在坟岔,假設(shè)我們要?jiǎng)?chuàng)建一個(gè)訪問令牌谒兄,其中令牌標(biāo)識(shí)是用戶名,我們還希望將用戶角色作為附加聲明存儲(chǔ)在令牌中社付。我們可以使用上一節(jié)討論的user_claims_loader()
裝飾器來實(shí)現(xiàn)這一點(diǎn)承疲。
但是,如果我們將用戶名傳遞給`user_claims_loader()`鸥咖,我們最終需要從數(shù)據(jù)庫(kù)查詢?cè)撚脩魞纱巍? * 1 第一次是當(dāng)?shù)卿浂它c(diǎn)被點(diǎn)擊時(shí)燕鸽,我們需要驗(yàn)證用戶名和密碼。
* 2 第二次是在`user_claims_loader()`函數(shù)中啼辣,因?yàn)槲覀冃枰樵冞@個(gè)用戶的角色啊研。這不是什么大事,但顯然它可以更有效率鸥拧。
在本章的方法中党远,提供了將任何對(duì)象傳遞給create_access_token()函數(shù)的能力,然后將該函數(shù)作為user_claims_loader()
傳遞富弦。這允許我們只訪問數(shù)據(jù)庫(kù)一次麸锉,但是引入了一個(gè)需要解決的新問題。我們?nèi)匀恍枰獜膶?duì)象中提取用戶名舆声,這樣我們就可以讓用戶名作為新令牌的標(biāo)識(shí)花沉。我們可以為此使用第二個(gè)裝飾器user_identity_loader()
柳爽,它允許您接收傳入create_access_token()
的任何對(duì)象,并從該對(duì)象返回一個(gè)json序列化的標(biāo)識(shí)碱屁。
請(qǐng)看示例代碼:
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è)用來構(gòu)建JWT數(shù)據(jù)的復(fù)雜對(duì)象
#看起來有點(diǎn)像SQLAlchemy 的實(shí)例
class UserObject:
def __init__(self, username, roles):
self.username = username
self.roles = roles
#定義jwt.user_claims_loader裝飾器磷脯,該裝飾器會(huì)在調(diào)用create_access_token函數(shù)時(shí)自動(dòng)被調(diào)用,
#user_claims_loader的參數(shù)就是傳遞給 create_access_token的參數(shù)
#user_claims_loader返回的數(shù)據(jù)會(huì)被保存到j(luò)wt 中赵誓,作為claims存在
@jwt.user_claims_loader
def add_claims_to_access_token(user):
return {'roles': user.roles}
#user_identity_loader裝飾器柿赊,該裝飾器會(huì)在調(diào)用create_access_token函數(shù)時(shí)自動(dòng)被調(diào)用,
#user_identity_loader的參數(shù)就是傳遞給 create_access_token的參數(shù)
#user_claims_loader返回的數(shù)據(jù)會(huì)被保存到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()