• flask搭建平台实战教程三:接口编写及权限校验(前后端分离)


    上一篇文章介绍了flask框架如何使用编写用户注册登录的功能

    下一步编写查询用户列表接口,使用flask_restful的marshal方法来生成字段数据,加上之前编写的login_required

    from flask import Blueprint,jsonify
    from flask_restful import fields, marshal
    from auth import login_required
    from models.user import User
    
    userbp = Blueprint('user',__name__,url_prefix="/user")
    
    user_fields = {
        'id': fields.Integer,
        'username': fields.String,
        'nickname': fields.String,
        'email': fields.String,
        'group_id': fields.Integer,
        '_create_time': fields.DateTime(dt_format='iso8601'),
        'update_time': fields.DateTime(dt_format='iso8601'),
    }
    
    @userbp.route("/list",methods=['GET'])
    @login_required
    def list():
        users = User.getall()
        return jsonify(code=201,msg="操作成功",data=marshal(users, user_fields))

    请求时header中不加入Authorization字段就会验证失败

    在header中添加Authorization,值为Bearer+空格+login返回数据的access_token,成功获取list接口数据

    用户的增删改查都是一样的逻辑来写

    from flask import Blueprint, jsonify
    from flask_restful import fields, marshal, reqparse
    from werkzeug.security import generate_password_hash
    
    from auth import login_required
    from models.user import User
    
    userbp = Blueprint('user',__name__,url_prefix="/user")
    
    user_fields = {
        'id': fields.Integer,
        'username': fields.String,
        'nickname': fields.String,
        'email': fields.String,
        'group_id': fields.Integer,
        '_create_time': fields.DateTime(dt_format='iso8601'),
        'update_time': fields.DateTime(dt_format='iso8601'),
    }
    
    @userbp.route("/list",methods=['GET'])
    @login_required
    def list():
        users = User.getall()
        return jsonify(code=201,msg="操作成功",data=marshal(users, user_fields))
    
    @userbp.route("/<uid>",methods=['GET'])
    @login_required
    def info(uid):
        user = User.getone(uid)
        return jsonify({
            "code": 0,
            "msg": "success",
            "data": marshal(user, user_fields)
        })
    
    @userbp.route("/add",methods=['POST'])
    @login_required
    def add():
        parser = reqparse.RequestParser()
        parser.add_argument("username", type=str, required=True, help="username is required")
        parser.add_argument("nickname", type=str, required=True, help="nickname is required")
        parser.add_argument('password', required=True, type=str, help='password is required')
        parser.add_argument('email', required=False, type=str)
        parser.add_argument('group_id', required=False, type=int, default=2)
        args = parser.parse_args()
        if User.exist(username=args['username']):
            return jsonify(code=400,msg="用户名已存在")
        args.update({'password': generate_password_hash(args['password'], salt_length=8)})
        User.add(args)
        return jsonify(code=201,msg="添加成功")
    
    @userbp.route("/edit",methods=['POST'])
    @login_required
    def edit():
        parser = reqparse.RequestParser()
        parser.add_argument("id", required=True, type=int, help="id is required")
        parser.add_argument("username", type=str, required=True, help="username is required")
        parser.add_argument("nickname", type=str, required=True, help="nickname is required")
        parser.add_argument('email', required=False, type=str)
        parser.add_argument('group_id', required=False, type=int)
        args = parser.parse_args()
        if not User.exist(id=args['id']):
            return jsonify(code=201,msg="用户不存在")
        User.edit(args)
        return jsonify(code=201,msg="修改成功")
    
    @userbp.route("/delete",methods=['GET'])
    @login_required
    def delete():
        parser = reqparse.RequestParser()
        parser.add_argument("id", required=True, type=int, location='args',help="id is required")
        args = parser.parse_args()
        if not User.exist(id=args['id']):
            return jsonify(code=201,msg="用户不存在")
        User.remove(args['id'])
        return jsonify(code=201, msg="删除成功")

    自定义权限校验

    之后为接口添加分组的权限校验,根目录添加文件router.py,编写路由装饰器

    routes ={}
    
    def route_meta(auth,endname):
    # endname必须是{Blueprint注册的名字.方法名}
    def wrapper(func): routes.setdefault(f"{endname}", auth) return func return wrapper

    在auth.py添加校验路由的装饰器

    def group_required(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            if not current_user.isadmin:
                auth = routes.get(request.endpoint)
                groupid = current_user.group_id
                authed = Auth.exist(group_id=groupid,auth=auth,endpoint=request.endpoint)
                if not authed:
                    return jsonify(code=10000,msg="权限不够,请联系超级管理员获得权限")
                return fn(*args,**kwargs)
            else:
                return fn(*args,**kwargs)
        return wrapper

    在add接口方法加上这两个装饰器,route_meta第二个参数必须是{Blueprint注册的名字.方法名}

    @route_meta("新增用户", "user.add")
    @userview.route("/add",methods=['POST'])
    @login_required
    @group_required
    def add():
      ......

    再次请求add接口会提示没有权限

    {
    "code": 10000,
    "msg": "权限不够,请联系超级管理员获得权限"
    }
     
    之后就需要为用户添加权限,权限关联到相关分组,所以添加修改分组接口
    @groupbp.route("/edit",methods=['POST'])
    @login_required
    def edit():
        parser = reqparse.RequestParser()
        parser.add_argument("id", required=True, type=int, help="id is required")
        parser.add_argument("name", required=True, type=str,  help="name is required")
        parser.add_argument("info", required=False, type=str)
        args = parser.parse_args()
        args['auths'] = request.json['auths']
        sql = select(Group).where(Group.name==args['name'],Group.id!=args['id'])
        if db.session.execute(sql).first():
            return jsonify(code=10000,msg="分组名已存在")
        Group.edit(args) # 需要重写edit
        return jsonify(code=201,msg="操作成功")

    由于修改分组需要添加、删除auth表的数据,所以要在models/group.py文件增加自己的edit方法

    from models.auth import Auth

    class Group:
    ......

    @classmethod def edit(cls, data): group = cls.getone(data['id']) group.name = data['name'] group.info = data['info'] for auth in group.auths: Auth.remove(auth.id) for item in data.get('auths'): authobj = Auth.add(dict(endpoint=item,auth=routes[item])) group.auths.append(authobj) db.session.commit()
    通过group/edit接口可以为admin分组增加权限

    上面接口成功的话就为admin增加了add和edit这两个方法的权限,再添加和修改用户就能成功了

    {
    "code": 201,
    "msg": "添加成功"
    }
     
    其它用户登录操作add、edit则会提示权限不够,当为delete方法添加group_required装饰器后,admin删除用户也会提示权限不够
     
    至此flask用户管理及权限验证的后台接口基本后端框架就完成了,还有一些细节需要自己去改进,然后就是选择前端框架编写前端页面。
  • 相关阅读:
    实现h5中radio单击取消与选中
    小程序中的组件化理解
    阿里字体css代码引入方法
    前端布局心得小结
    Python学习资源汇总,转载自他人
    史上最全 原生javascript的知识总结,适合新手及查资料用!
    windows Python 3.4.3 安装图文
    PyInstaller编译python3时使用的详细参数介绍
    PyInstaller 安装方法 及简单的编译exe (python3)
    Windows 安装 GTK+ 图文说明
  • 原文地址:https://www.cnblogs.com/zerotest/p/16797023.html
Copyright © 2020-2023  润新知