前后端分离架构下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 requestfrom 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 JWTManagerapp = 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"}), 401access_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_identitycurrent_user = get_jwt_identity()return jsonify(logged_in_as=current_user), 200if __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.datapassword = form.password.dataadmin = 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": "用户名或密码错误!"}), 401return jsonify({"msg": "用户名或密码错误!"}), 401return 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 只是一种实现方案,实际的项目开发中,会根据具体情况选择合适的鉴权方法。