1.首先需要在前端main.vue文件中加入拦截器,目的是每次访问的时候都把token带着:
// 设置一个拦截器,作用:每次请求时,将token加到那个包上,这样就可以将token发送到服务端
axios.interceptors.request.use(
// 这个config表示页面向服务器发送的数据,拦截下来
config => {
const tokenstr = window.sessionStorage.getItem('token')
if (tokenstr) {
// 为拦截下来的包加入token
config.headers.token = tokenstr
}
// 最后将加入token的包从新发出去
return config
}
)
// 设置一个相应拦截器
// 作用:当服务端返回时,有token失效或错误的状态码时,就改一下他的path让他跳转到登录页面
axios.interceptors.response.use(
response => {
// console.log(response)
if (response.data.status === 10016 || response.data.status === 10017) {
// 这个路由就是服务器返回的,然后把他里面的路径换一下
router.replace(
{
path: '/login'
}
)
}
return response
}
)
2.建议在路由文件(router.vue的最下面)中把守卫钩子函数加上:
router.beforeEach((to, from, next) => {
if (to.path === '/login') return next()
const tokenstr = window.sessionStorage.getItem('token')
if (!tokenstr) return next('/login')
// 用户不去登录页,并且已登录过,放行
next()
})
3.可以选择加入token验证,在一个文件下,例如utils文件夹下,创建一个文件token.py
'''
专门设置tokens的文件
需要用到:
加密的数据:uid
算法:python模块
密钥:flask_app SECRET_KEY
原理:
避免像session那种将用户数据存储到服务器上。
根据用户登陆过就会通过数据和密钥用加密算法生成一个tokens,然后再发送给客户端
以后客户登录就带着这个tokens,
'''
# 得到app config中的盐
from flask import current_app,request,g
# 导入加密算法
from itsdangerous import URLSafeTimedSerializer as Serializer
from flask_student.models import User
from flask_student.utils.message import to_dict_msg
from flask_student import models
from functools import wraps
# 导入元装饰器
import functools
# 加密函数(加密内容,加密时间)
def generate_auth_token(uid,expiration):
# 创建加密对象(密钥)
s = Serializer(current_app.config['SECRET_KEY'])
#生成tokens(加密的内容,加密时间)
return s.dumps({'id':uid,'exp':expiration})
# 解密函数
def verify_auth_token(token_str):
# 创建解密对象(密钥)
s = Serializer(current_app.config['SECRET_KEY'])
# 防止那个token不存在或黑客恶意攻击
try:
# 解密tokens对象,变成字典
data = s.loads(token_str)
except Exception:
return to_dict_msg(10017)
usr = User.query.filter_by(id = data.get("id")).first()
return usr
# tokens装饰器函数(用户登录装饰器)
def login_required(view_func):
@wraps(view_func) # 这里需要 @ 符号
def verify_token(*args, **kwargs):
# 更安全地获取 token
token = request.headers.get("token")
if not token:
return to_dict_msg(10016, msg='缺少token')
# 创建解密对象
s = Serializer(current_app.config['SECRET_KEY'])
try:
# 解密 token
data = s.loads(token)
except Exception:
return to_dict_msg(10017, msg='token无效或已过期')
# 验证用户是否存在
user_id = data.get('id')
if not user_id:
return to_dict_msg(10018, msg='token格式错误')
user = models.User.query.get(user_id)
if not user:
return to_dict_msg(10003, msg='用户不存在')
# 设置 g 对象供后续使用
g.user = user
g.user_id = user_id
g.token_data = data
return view_func(*args, **kwargs)
return verify_token
4.还在utils文件夹下创建文件 userPermission.py
from flask_student import models
from flask_student.utils.tokens import login_required
from flask_student.utils.message import to_dict_msg
from functools import wraps
from flask import g
'''
这是不同用户有不同权限
'''
# 用户权限加的两个普通的方法
def get_user_permissions(user_id):
"""获取用户所有权限"""
user = models.User.query.get(user_id)
if not user or not user.role:
return []
permissions = []
role = user.role
# 遍历角色拥有的所有菜单权限(路径就是权限,否者其他的是)
for menu in role.menu:
if menu.path: # 只有有路径的菜单才算是权限
permissions.append(menu.path)
return permissions
def get_user_menu(user_id):
"""获取用户菜单树"""
user = models.User.query.get(user_id)
if not user or not user.role:
return []
return user.role.to_menu_list()
def permission_required(permissions=None):
"""权限验证装饰器"""
def decorator(f):
@wraps(f)
@login_required
def decorated_function(*args, **kwargs):
# 如果不需要权限。就执行路由函数
if not permissions:
return f(*args, **kwargs)
# 当前的用户
user_id = g.user_id
# user_id = session.get('user_id')
if not user_id:
return to_dict_msg(10002, msg='请先登录')
# 获取当前用户的权限
user_permissions = get_user_permissions(user_id)
# 需要的权限
required_perms = set(permissions)
# 用户的权限
# set的作用 1.去重,2.能用集合运算issubset()
user_perm_set = set(user_permissions)
# 判断用户权限是否是所需权限的子集
if not required_perms.issubset(user_perm_set):
return to_dict_msg(10005, msg='权限不足')
return f(*args, **kwargs)
return decorated_function
return decorator
3.上面两个准备好,不要忘了,在login路由中,但是如果有token验证,这前两行代码就可以不加了。
# 这是用户权限所需要的代码
session['user_id'] = usr.id
session['user_name'] = usr.username
permissions = get_user_permissions(usr.id)
menus = get_user_menu(usr.id)
5.然后就可以在需要加验证的路由下面就可以加上验证装饰器了
例如这样:(一定要加在下面,否则不会生效)
@student.route('/student_list')
@permission_required(['/role_list'])
6.最后补充:
其实只有3,4,5才是权限设置的问题,前两个只是为了保证项目的完整性,使我们设置的能运行出来,如果是仅仅用postman测验的话,1,2是不需要的