Flask开发日记-权限校验

2,132 阅读2分钟

这是我参与更文挑战的第12天,活动详情查看: 更文挑战

业务场景

首先, 权限控制有两种方式: RBAC和ACL

RBAC是基于角色的控制方式, 而ACL中权限直接与用户相关

Flask在笔者理解的初衷是快准狠, 所以我们放弃了较为复杂的ACL, 使用RBAC进行权限管理

根据RBAC的理念, 简单讲述下系统的权限构建:

  1. 使用接口/权限/角色/用户四个概念来进行控制, 并创建对应的表
  2. 创建接口与权限、权限与角色, 以此类推的关系表
  3. 用户登陆时查询所拥有的接口信息
  4. 访问接口时进行校验

其中的前三步网上已经有非常多的案例了, 代码也十分简单(除了树形关系处理)

本文着重讲一下第四步, 利用Python的装饰器实现接口校验

方案

问题思路

在设计权限校验时, 第一反应是根据请求的url进行匹配

例如接口为/api/user, 则在用户的接口信息中进行匹配, 如果不存在则没有对应权限

但对于endpoint格式的接口, 这里就出现难题了, /api/user/1怎么处理呢?

很多小伙伴肯定能想到正则, 但这样还需要为不同的接口定制规则, 且资源id的不同甚至会影响到接口的设计, 不具备适用性

所以, 正确的做法应该是使用代码, 为接口确定代码并进行校验

编写装饰器

明确了解决方案后, 我们开始编写代码

第一步, 安装flask_jwt_extended, 为什么使用token就不需要再说明了吧

第二步, 编写一个带有接口代码的装饰器:

from functools import wraps

from flask_jwt_extended import verify_jwt_in_request, get_jwt

from flask_koala.core.exceptions import BusinessException


def authorization(code: str = None):
    """
    鉴权装饰器
    """

    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            try:
                verify_jwt_in_request()
            except Exception:
                raise BusinessException("无访问权限", 403)
            if code is None:
                return fn(*args, **kwargs)
            authorities = get_jwt()['authorities']
            if code not in authorities:
                raise BusinessException("无访问权限", 403)
            return fn(*args, **kwargs)

        return wrapper

    return decorator

这里我使用了全局自定义异常, 把BusinessException换成你需要的即可

最后一步, 只需要在接口上加上注解即可:

@auth.route('/info')
class Info(Resource):
    @authorization(code='api:auth:info')
    def get(self):
        """
        获取用户信息
        :return: 用户信息实体
        """
        return RestResult.success(get_jwt_identity())