Flask+Vue-Router+JWT实现登录验证

发布于:2025-03-18 ⋅ 阅读:(129) ⋅ 点赞:(0)

目录

简要

后端Flask代码

secret.py

main.py

前端Vue3代码

router.js

api.js

登录组件

简要

后端:Flask

前端:Vue3

实现功能

  1. 实现登录验证,只有用户登录后,才可以访问某些特定的页面
  2. 实现登录状态保存,当用户登陆后,可以保持一段时间的登录状态,在此期间无需再次登录
  3. 实现JWT的过期验证、安全验证

在此之前,后端需要安装如下Python库

pip install PyJWT

前端需要安装如下

npm install axios

实现思路

  1. 当用户登陆后,由后端Flask生成一个经过加密的token(内含用户id、过期时间),并发送给前端
  2. 前端保存token(使用localStorage)
  3. 前端每次访问页面,首先判断该页面是否需要登录,如果需要登录判断此时是否登录,如果登录判断token是否合法(交由后端解密token判断)
  4. 若不合法,则跳转到登录页面

具体流程图如下图所示:

后端Flask代码

为方便管理,将生成、验证token的代码,单独拿出来作为一个py文件(secret.py)

路由函数单独在(main.py)中

secret.py

import jwt
import secrets
from datetime import datetime,timedelta

# 生成token密钥
secret_key = secrets.token_hex(32)

#jwt函数
def generate_jwt(user_id):
    """
    生成 JWT 令牌
    :param user_id: 用户 ID
    :return: 生成的 JWT 令牌
    """
    payload = {
        'user_id': user_id,
        'exp': datetime.utcnow() + timedelta(minutes=30)  # 设置过期时间为 30 分钟后
    }
    token = jwt.encode(payload,secret_key,algorithm='HS256')
    return token

def verify_jwt(token):
    """
    验证 JWT 令牌
    :param token: 待验证的 JWT 令牌
    :return: 若验证通过,返回用户 ID;否则返回 None
    """
    try:
        data = jwt.decode(token,secret_key,algorithms=['HS256'])
        exp = data.get('exp')
        if exp and datetime.utcfromtimestamp(exp) < datetime.utcnow():
            return None
        return data.get('user_id')
    except:
        return None

#仅返回用户id
def get_token(token):
    data = jwt.decode(token,secret_key,algorithms=['HS256'])
    return data.get('user_id')

main.py

#JWT相关
import secret as key
#flask相关
from flask import Flask,request,jsonify
from flask_cors import CORS

app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = key.secret_key

CORS(app)

#jwt函数
@app.route('/check_token', methods=['GET'])
def check_token():
    """
    检查 JWT 令牌是否有效且未过期
    """
    token = request.headers.get('Authorization')
    if not token:
        return jsonify({'code':401,'message': 'token缺失'})
    user_id = key.verify_jwt(token)
    if user_id:
        return jsonify({'code':200,'message': 'token合法', 'user_id': user_id})
    return jsonify({'code':401,'message': 'token不合法'})

前端Vue3代码

同样为了方便管理,在前端中,将Vue-Router配置单独写进(router.js)文件中。

检查token函数单独写进(api.js)中

至于保存token代码,写在登录组件中即可

router.js

router.beforeEach(async (to,from,next) => {
    const token = localStorage.getItem('access_token');
    // 判断是否需要验证登录
    if (to.meta.requireAuth){
        // 没有token
        if (!token) {
            next({name: 'login'});
        }
        else {
            // 有token,检查token是否过期、是否合法
            try {
                const response = await axios.get('http://127.0.0.1:5000/check_token',{
                    headers:{
                        Authorization:`${token}`
                    }
                });
                // 合法直接跳转
                if (response.data.code == 200){
                    next();
                }
                // 过期或非法,重新登录
                else{
                    localStorage.removeItem('access_token');
                    next({name: 'login'});
                }
            }
            // 网络错误,重新登录
            catch (error) {
                localStorage.removeItem('access_token');
                next({name: 'login'});
            }
        }
    }
    // 不需要直接跳转
    else {
        next();
    }
})

这里的meta是一个自定义属性,当某路由需要登录验证时,只需在路由处添加meta属性即可,如下所示:

{
    //有meta属性,需要登录验证
    path:'/test1',
    component:() => import('test1.vue'),
    meta:{
        requireAuth:true
    }
},
{
    //没有meta属性,不需要登录验证
    path:'/test2',
    component:() => import('test2.vue'),
},

api.js

import axios from 'axios'
//检查token是否过期
export async function check_token(token){
    try {
        const reponse = await axios.get('http://127.0.0.1:5000/check_token',{
            headers:{
                Authorization:`${token}`
            }
        });
        return reponse.data;
    }
    catch (error) {
        return error;
    }
}

登录组件

这里只需要登陆后,保存token即可

import axios from 'axios';
async function login(data){
    try {
        const response = await axios.post('http://127.0.0.1:5000/user/login',data);
        return response.data;
    }
    catch (error) {
        return error
    }
}

async function upload(data){
    try {
        const response = await login(data);
        if (response.code == 200){
            //存储token
            localStorage.setItem('access_token',response.access_token);
            /... 其他操作 ... /
        }
        else {
            console.log(error);
        }
    }
    catch (error) {
        console.log(error);
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到