当前位置: 首页 > news >正文

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

目录

简要

后端Flask代码

secret.py

main.py

前端Vue3代码

router.js

api.js

登录组件

一些方法的介绍

1.前端

1.1localStorage

1.1.1localStorage.setItem(key,value)

1.1.2localStorage.getItem(key)

1.1.3localStorage.removeItem(key)

1.1.4localStorage.clear()

1.1.5localStorage.length

1.2sessionStorage

 1.1.1sessionStorage.setItem(key,value)

1.1.2sessionStorage.getItem(key)

1.1.3sessionStorage.removeItem(key)

1.1.4sessionStoragee.clear()

1.1.5sessionStorage.length

2.后端

2.1JWT

简要

后端: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 tokendef 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 Nonereturn 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

首先从request请求的headers中获取“Authorization”请求头,该请求头包含前端发送的token

#JWT相关
import secret as key
#flask相关
from flask import Flask,request,jsonify
from flask_cors import CORSapp = Flask(__name__)
app.config['JWT_SECRET_KEY'] = key.secret_keyCORS(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

import axios from 'axios'
router.beforeEach(async (to,from,next) => {const token = localStorage.getItem('access_token');// 判断是否需要验证登录if (to.meta.requireAuth){// 没有tokenif (!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';
// 登录
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}
}//检查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 {login} from api;
async function upload(data){try {const response = await login(data);if (response.code == 200){//存储tokenlocalStorage.setItem('access_token',response.access_token);/... 其他操作 ... /}else {console.log(error);}}catch (error) {console.log(error);}
}

一些方法的介绍

在这里将介绍一下前端后端用到的一些方法

1.前端

1.1localStorage

localStorageHTML5新增的一个会话存储对象,用于保存某页面的数据,在关闭页面后数据不会被清除,除非主动删除,否则会永远存在

  • 数据存储:将数据以键值对的形式存储在浏览器中,这些数据会一直保留在浏览器中,直到手动清除
  • 作用域:数据是基于源(协议、域名、端口)的,不同源的页面无法互相访问对方的localStorage
  • 存储大小:通常是5MB
  • 数据类型:localStorage只能存储字符串类型的数据
1.1.1localStorage.setItem(key,value)
  • 功能:用于向localStorage中添加数据
// 存储一个字符串
localStorage.setItem('username','John');//存出一个对象,需要先转换为JSON字符串
const user = {name:'Jane',age:25
};
localStorage.setItem('user',JSON.stringify(user));
1.1.2localStorage.getItem(key)
  • 功能:从localStorage中获取指定键对应的值
//获取存储的字符串
const username = localStorage.getItem('username');//获取存储的对象,需要将JSON字符串转换为对象
const userJSON = localStorage.getItem('user');
const userObj = JSON.parse(userJSON);
1.1.3localStorage.removeItem(key)
  • 功能:从localStorage中删除指定键和对应的数据
//移除username数据
localStorage.removeItem('username');
1.1.4localStorage.clear()
  • 功能:清除localStorage中所有的键和数据
//清除所有存储的数据
localStorage.clear();
1.1.5localStorage.length
  • 定义:localStorage的一个属性
  • 功能:返回localStorage中存储的键值对的数量
//返回localStorage中存储的键值对的数量
const count = localStorage.length;

1.2sessionStorage

sessionStorageHTML5新增的一个会话对象,用于临时保存某页面的数据,在关闭页面后数据会被清除

  • 数据存储:以键值对的形式存储数据,但数据仅在当前会话期间有效
  • 作用域:基于源(协议、域名、端口)的,不同页面之间无法互相访问对方的sessionStorage,即不同页面之间的数据相互独立
  • 存储大小:通常是5MB
  • 数据类型:只能存储字符串类型的数据
 1.1.1sessionStorage.setItem(key,value)
  • 功能:用于向sessionStorage中添加数据
// 存储一个字符串
sessionStorage.setItem('username','John');//存出一个对象,需要先转换为JSON字符串
const user = {name:'Jane',age:25
};
sessionStorage.setItem('user',JSON.stringify(user));
1.1.2sessionStorage.getItem(key)
  • 功能:从sessionStorage中获取指定键对应的值
//获取存储的字符串
const username = sessionStorage.getItem('username');//获取存储的对象,需要将JSON字符串转换为对象
const userJSON = sessionStorage.getItem('user');
const userObj = JSON.parse(userJSON);
1.1.3sessionStorage.removeItem(key)
  • 功能:从sessionStorage中删除指定键和对应的数据
//移除username数据
sessionStorage.removeItem('username');
1.1.4sessionStoragee.clear()
  • 功能:清除sessionStorage中所有的键和数据
//清除所有存储的数据
sessionStorage.clear();
1.1.5sessionStorage.length
  • 定义:sessionStorage的一个属性
  • 功能:返回sessionStorage中存储的键值对的数量
//返回sessionStorage中存储的键值对的数量
const count = sessionStorage.length;

2.后端

2.1JWT

PyJWT中,有encode(编码)decode(解码)两个主要方法:

encode(payload,secret_key,algorithm)方法生成一个JWT格式的token:

  • pyload:JWT的主要组成部分,用来存储传递的数据,例如可以存储用户id、过期时间等等
  • secret_key:生成token的密钥,没有密钥无法解析token
  • algorithm:JWT的编码格式

decode(token,secret_key,algorithm)方法解析一个JWT格式的token:

  • token:需要解析的token
  • secret_key:token的密钥
  • algorithm:JWT的编码格式

由此可见,一个JWT的安全由:“secret_key密钥”和“algorithm编码格式”两部分来维护

在实际应用中,应尽可能的生成复杂的密钥,并且定时更换密钥


http://www.mrgr.cn/news/94843.html

相关文章:

  • 项目实战系列:基于瑞萨RA6M5构建多节点OTA升级-系统设计<一>
  • 【WRF数据准备】 基于CDO/Python 拼接 grib 数据:如ERA5 气象数据
  • 设计模式之外观模式:原理、实现与应用
  • HarmonyOS三层架构实战
  • 【Linux内核系列】:进程板块与文件板块的综合
  • C# 一文读懂委托与事件
  • 【C++进阶一】STL和string
  • Python集合
  • 【MySQL基础-9】深入理解MySQL中的聚合函数
  • SpringCloud 学习笔记2(Nacos)
  • 数据结构篇——二叉树的存储与遍历
  • GaussDB备份数据常用命令
  • SSM框架——Spring面试题
  • 汇编基础知识
  • [HelloCTF]PHPinclude-labs超详细WP-Level 0
  • 解决git init 命令不显示.git
  • C++基础 [五] - String的模拟实现
  • Mock接口编写教程-axios-mock-adapter(React)
  • StarRocks + Paimon 在阿里集团 Lakehouse 的探索与实践
  • Python中的time模块