用講故事的方法講述 JWT
JWT 就像一張門禁卡
小明管理著一個小區(qū)的物業(yè),負責整個小區(qū)的出入安全。剛開始的時候小明決定要保險一點,所有出入小區(qū)的都要驗證業(yè)主的本人信息。
所以他搞了個規(guī)定,每個進小區(qū)的人都要驗證身份證和指紋,通過后臺證明你是業(yè)主才讓你進去。剛開始的時候這個規(guī)定還行,但是隨著小區(qū)的出入人員變多,處理速度太慢,小區(qū)業(yè)主經(jīng)常需要排隊進入小區(qū)。
收到了大量的投訴電話只后小明決定反思一下,決定使用門禁卡來解決這個效率問題。他于是讓業(yè)主去物業(yè)做一個一次性的身份驗證,通過了之后就發(fā)一張門禁卡給業(yè)主,不過門禁卡有期限限制,半年之后就需要更新一下,而且業(yè)主刷卡的時候,物業(yè)只需要驗證下這是不是我們發(fā)的業(yè)主卡就行了。
物業(yè)在處理門禁卡信息的時候,會從門禁卡里面解密信息,那個信息里面帶有業(yè)主自己本人的信息。
在這個故事里面,
- 第一個的每次進入小區(qū)都需要驗證就是傳統(tǒng)的session登錄方法
- 門禁卡制度就是jwt
用python實踐 JWT
使用JWT實踐的方法很簡單,就是分三部分。
- 服務器驗證是否是用戶
- 服務器為用戶生成一個TOKEN
- 用戶訪問服務器的時候帶著那個TOKEN
- 服務驗證TOKEN是否合法
- 用戶訪問內容
完整的例子
from flask import Flask, jsonify, request
from flask_jwt_extended import (
JWTManager, jwt_required, create_access_token,
get_jwt_identity
)
app = Flask(__name__)
# Setup the Flask-JWT-Extended extension
app.config['JWT_SECRET_KEY'] = 'super-secret' # Change this!
jwt = JWTManager(app)
# Provide a method to create access tokens. The create_access_token()
# function is used to actually generate the token, and you can return
# it to the caller however you choose.
@app.route('/login', methods=['POST'])
def login():
if not request.is_json:
return jsonify({"msg": "Missing JSON in request"}), 400
username = request.json.get('username', None)
password = request.json.get('password', None)
if not username:
return jsonify({"msg": "Missing username parameter"}), 400
if not password:
return jsonify({"msg": "Missing password parameter"}), 400
if username != 'test' or password != 'test':
return jsonify({"msg": "Bad username or password"}), 401
# Identity can be any data that is json serializable
# 服務器為用戶生成一個TOKEN
access_token = create_access_token(identity=username)
return jsonify(access_token=access_token), 200
# Protect a view with jwt_required, which requires a valid access token
# in the request to access.
@app.route('/protected', methods=['GET'])
@jwt_required
def protected():
# Access the identity of the current user with get_jwt_identity
# 服務驗證TOKEN是否合法
current_user = get_jwt_identity()
# 用戶訪問內容
return jsonify(logged_in_as=current_user), 200
if __name__ == '__main__':
app.run()
運行該程序
- 用戶如何獲得token
curl -H "Content-Type: application/json" -X POST \
-d '{"username":"test","password":"test"}' http://localhost:5000/login
代碼會返回類似于
{"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6dHJ1ZSwianRpIjoiZjhmNDlmMjUtNTQ4OS00NmRjLTkyOWUtZTU2Y2QxOGZhNzRlIiwidXNlcl9jbGFpbXMiOnt9LCJuYmYiOjE0NzQ0NzQ3OTEsImlhdCI6MTQ3NDQ3NDc5MSwiaWRlbnRpdHkiOiJ0ZXN0IiwiZXhwIjoxNDc0NDc1NjkxLCJ0eXBlIjoiYWNjZXNzIn0.vCy0Sec61i9prcGIRRCbG8e9NV6_wFH2ICFgUGCLKpc"}
- 用戶訪問的過程中帶上token
export ACCESS="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6dHJ1ZSwianRpIjoiZjhmNDlmMjUtNTQ4OS00NmRjLTkyOWUtZTU2Y2QxOGZhNzRlIiwidXNlcl9jbGFpbXMiOnt9LCJuYmYiOjE0NzQ0NzQ3OTEsImlhdCI6MTQ3NDQ3NDc5MSwiaWRlbnRpdHkiOiJ0ZXN0IiwiZXhwIjoxNDc0NDc1NjkxLCJ0eXBlIjoiYWNjZXNzIn0.vCy0Sec61i9prcGIRRCbG8e9NV6_wFH2ICFgUGCLKpc"
然后訪問接口
curl -H "Authorization: Bearer $ACCESS" http://localhost:5000/protected
最后返回
{
"logged_in_as": "test"
}