flask框架-认证(三):重写view.MethodView类,实现token认证,flask实现token,flask生成token,推荐的flask的token写法

环境:

alembic==1.8.1
click==7.1.2
Flask==1.1.4
Flask-Migrate==2.7.0
Flask-Script==2.0.6
Flask-SQLAlchemy==2.4.1
greenlet==2.0.1
importlib-metadata==5.0.0
importlib-resources==5.10.0
itsdangerous==1.1.0
Jinja2==2.11.3
Mako==1.2.4
MarkupSafe==2.0.1
PyMySQL==1.0.2
SQLAlchemy==1.3.0
typing_extensions==4.4.0
Werkzeug==1.0.1
zipp==3.10.0
Flask-RESTful==0.3.9
PyJWT==2.7.0
websocket-client==1.5.1
gevent==22.10.1
gevent-websocket==0.10.1
Flask-Caching==2.0.2
redis==4.5.5

一、项目结构

项目:

        --apps

                --user

                --__init__.py

        --base

                --authen.py

                --view.py

                --response.py

二、写token认证

base/authen.py

from flask import request,g
import jwt
import time
from flask import jsonify
from functools import wraps #类装饰器
#导入用户表:这个根据用户自己来
from apps.user.models import UserModel
 
 
JWT_SECRET_KEY = '$#%^&&*(DFHJKUTYGHF112312' #加密的盐
ALGORITHM = 'HS256' #加密算法
 
#生成token
def jwt_encode_token(user_id:int,time_out=7*24*60*60):
    payload = {
        'user_id': user_id,
        'iat': time.time(), #产生token时的时间戳
        'exp': time.time() + time_out #token过期时间戳
    }
    token = jwt.encode(payload, JWT_SECRET_KEY, algorithm=ALGORITHM)
    return token
 
#解析token
def jwt_decode_token(token):
    secret = JWT_SECRET_KEY
    payload = jwt.decode(token,secret,algorithms=ALGORITHM)
    return payload
 
 
#类装饰器:需要认证
def login_required(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        token = request.cookies.get('token', "none")
        if not token:
            token = request.headers.get('token', "none")
        try:
            payload = jwt_decode_token(token)
        except Exception as e:
            return jsonify({'code': 410, 'error': 'token有问题'}),403
        user_id = payload.get('user_id')
        exp = payload.get('exp')
        now = time.time()
        obj = UserModel.query.filter_by(id=user_id).first()
        if not obj:
            return jsonify({'code': 410, 'error': 'token有问题'}),403
        if exp < now:
            return jsonify({'code': 410, 'error': 'token已经过期了'}),403
        g.user = obj
        #认证通过,执行视图函数
        return func(*args,**kwargs)
    return wrapper
 
 
#管理员权限才能访问的: 依赖于login_required装饰器,后续如果有其他权限要求,可以仿照这个来写
def authen_admin_required(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if not hasattr(g,'user'):
            return jsonify({'code':410,'msg':'请先登录'}), 403
        if g.user.role != '管理员':
            return jsonify({'code': 410, 'msg': '没有管理员权限,无法操作'}), 403
        # 认证通过,执行视图函数
        return func(*args, **kwargs)
 
    return wrapper

if __name__ == '__main__':
    token = jwt_encode_token(78)

三、重写flask的views.MethodView

1、其内部有decorators = () 类变量,用来接收装饰器的,在执行请求前,会先执行里面的装饰器的,再去执行对应的请求函数。所以,如果要限制请求,就将限制的装饰器放到这个类变量中即可

2、构建一个视图类基类,后续自己写的所有的视图都继承该视图类,这样就可以通过操作decorators来实现全局使用和局部禁用token认证了。

3、拓展:频率限制也可以通过这个来

base/view.py

from flask import views
from apps.authen import login_required
class HttpView(views.MethodView):
    decorators=[login_required]
    pass

四、视图使用

1、登录接口: 无需检验token就可以访问

from apps.user import model
from base.authen import jwt_encode_token
from base.view import HttpView
class LoginView(HttpView):
    #认证,局部禁用,登录接口无需验证token
    decorators = []
    def post(self):
        user = request.form.get('user')
        password = request.form.get('password')
        user = model.usermodel.query.filter(username=user,password=password).first()
        if not user:
            return jsonify({'code':400,'msg':'用户名或密码错误'})
        else:
            token = jwt_encode_token(user.id)
            dic={'code':200,'token':token,'user':user.id}
            response = make_response(dic)
            response.set_cookie('token',token , httponly=False)
            return response

2、需要检验token的接口:需要检验token

from base.view import HttpView
from flask import jsonify
class OtherView(HttpView):
    def get(self):
        return jsonify({'code':200,'msg':'需要登录才能访问'})

3、管理员才能访问的接口:需要检验用户的权限

from flask import jsonify
from base.view import HttpView
from base.authen import login_required,admin_required

#管理员权限控制
class AdminView(HttpView):
    decorators = [login_required,admin_required]
    def post(self):
        return jsonify({'code':200,'msg':'需要管理员角色才能访问'})

#管理员权限控制:推荐使用这个
class AdminView2(HttpView):
    @admin_required
    def post(self):
        return jsonify({'code':200,'msg':'需要管理员角色才能访问'})

局限性:

1、在项目中,所有的CBV,都必须继承自己写的HttpView类

2、在项目中,不能使用FBV,无法控制到FBV的请求

其他全局和局部控制的方法:

1、使用中间件:对所有请求都要求认证

        不需要认证:在中间件中,判断url来确定不用token,如:登录功能

        需要特定角色:在视图上加 @admin_required 装饰器

        https://blog.csdn.net/weixin_46371752/article/details/131140289icon-default.png?t=N6B9https://blog.csdn.net/weixin_46371752/article/details/131140289

2、纯手写 :【不推荐,不适合偷懒】

        不需要认证:就不写

        需要认证:视图上加上,decorators=[login_required]

        需要特定角色:视图上加上,decorators=[login_required],请求函数上加@admin_required 装饰器

你可能感兴趣的:(flask,python,后端)