前后端分离架构下JWT实现用户鉴权
在【计算机网络】JWT(JSON Web Token)初识 中,我们讲解了 JWT 的基础知识。Token 验证的方式一般是用在前后端分离的软件开发项目中,所以本篇文章将会从前端和后端的角度去考虑 JWT 的实现。前端 Vue,后端 Flask。
1.flask-jwt-extended
首先要介绍一个 Python 包,flask-jwt-extended,用于生成 Token 和验证 Token,使用起来非常方便。
pip install flask-jwt-extended
from flask import Flask
from flask import jsonify
from flask import request
from flask_jwt_extended import create_access_token
from flask_jwt_extended import get_jwt_identity
from flask_jwt_extended import jwt_required
from flask_jwt_extended import JWTManager
app = Flask(__name__)
# Setup the Flask-JWT-Extended extension
app.config["JWT_SECRET_KEY"] = "super-secret" # Change this!
jwt = JWTManager(app)
# Create a route to authenticate your users and return JWTs. The
# create_access_token() function is used to actually generate the JWT.
@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
access_token = create_access_token(identity=username)
return jsonify(access_token=access_token)
# Protect a route with jwt_required, which will kick out requests
# without a valid JWT present.
@app.route("/protected", methods=["GET"])
@jwt_required()
def protected():
# Access the identity of the current user with get_jwt_identity
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
if __name__ == "__main__":
app.run()
我们可以利用 Postman 测试一下:
(1)不登录直接请求 protected 接口。
(2)测试登录接口。
(3)在 Authorization 中添加相关的 Token 信息,再次请求 protected 接口。
2.后端实例
我们来看一个实际的项目,后端的登录接口如下。
from flask_jwt_extended import create_access_token
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
username = form.username.data
password = form.password.data
admin = Admin.query.filter(Admin.username == username).first()
if admin:
if username == admin.username and password == admin.password:
access_token = create_access_token(identity=username)
return jsonify(access_token=access_token)
return jsonify({"msg": "用户名或密码错误!"}), 401
return jsonify({"msg": "用户名或密码错误!"}), 401
return jsonify({"msg": "请重新登录!"}), 401
再来看另外一个接口,是需要登录成功后才能请求到数据。
from flask_jwt_extended import jwt_required
@home_bp.route('/search')
@jwt_required()
def search():
......
return json.dumps(data, ensure_ascii=False)
3.前端实例
用户提交登录表单后,触发登录处理方法,获取 Token,存到 localStorage 中。
handleLogin() {
this.$axios({
method:"post",
url:'auth/login',
data:{username: this.loginForm.username, password: this.loginForm.password},
headers:{'Content-Type': 'multipart/form-data'},
withCredentials: true
}).then(res => {
localStorage.setItem("token",res.data.access_token);
this.$router.push('/xxxxxx');
})
}
其中的一个请求如下,需要在头部 headers 将 Authorization 设置为 Token 的值,后端 Token 验证通过才能获取到数据。
getInfo() {
this.$axios({
method:"get",
url:'search',
headers: {
Authorization: "Bearer " + localStorage.getItem('token'),
},
})
.then((res) => {
this.tableData = res.data;
})
}
虽然用户登录是一个很基础的功能,但是要理解透彻这一块的知识点并不容易,我觉得核心在于对网络请求的理解。JWT 只是一种实现方案,实际的项目开发中,会根据具体情况选择合适的鉴权方法。