Flask权限管理

权限管理是一个很常见的功能模块,本文基于RBAC模型针对于多用户,多角色,多权限的场景,介绍一种Flask权限管理方案。

Flask系列文章

  1. Flask开发初探
  2. WSGI到底是什么
  3. Flask源码分析一:服务启动
  4. Flask路由内部实现原理
  5. Flask容器化部署原理与实现

本文将在开发初探的代码基础上进行重构。

介绍

在本文所述场景中,具体的权限管理是:权限和角色关联,给用户添加角色,用户即拥有角色的权限,也就是基于角色的权限控制。当然,若需要基于用户的权限控制也是可以的,只需要修改下相关数据结构即可。

具体的权限验证采用了位运算,将权限值用十六进制表示,每个角色拥有一个权限总值,当判断该角色是否有特定权限时:

In [1]: permission = 0X02

In [2]: permissions = 0X0D

In [3]: print((permissions & permission) == permission)
False

In [4]: permissions = 0X07

In [5]: print((permissions & permission) == permission)
True

返回值为True表示拥有该权限,False为没有该权限,原理与位运算的原理有关。

0x07 = 0x01 + 0x02 + 0x04

转换为二进制数值可以看做是:0111 = 0001 + 0010 + 0100

按照位运算,运算符&(按位与)相应位都为1,则该位为1,否则为0,那么权限总值和权限值执行按位与运算,结果恒为权限值时才能得出拥有该权限。

实现

创建

首先,针对以上场景,我们创建数据表。

用户

创建用户表,保存用户信息和对应的角色:

class User(db.Model):
    """
    用户表
    """
    __tablename__ = "user"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), unique=True)
    email = db.Column(db.String(128))
    password = db.Column(db.String(128))
    role_id = db.Column(db.Integer)

    def __init__(self, name, email, password):
        self.name = name
        self.email = email
        self.password = bcrypt_sha256.encrypt(str(password))

权限

创建权限类,赋予每种操作权限值,这里举例用户管理和更新权限:

class Permissions:
    """
    权限类
    """
    USER_MANAGE = 0X01
    UPDATE_PERMISSION = 0x02

角色

需要创建角色表结构,我们暂定两种角色:普通用户和管理员,并初始化角色和权限。

class Role(db.Model):
    """
    角色表
    """
    __tablename__ = "role"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), unique=True, commit="角色名")
    permissions = db.Column(db.Integer, commit="权限总值")

    @staticmethod
    def init_role():
        role_name_list = ['user', 'admin']
        roles_permission_map = {
            'user': [Permissions.USER_MANAGE],
            'admin': [Permissions.USER_MANAGE, Permissions.UPDATE_PERMISSION]
        }
        try:
            for role_name in role_name_list:
                role = Role.query.filter_by(name=role_name).first()
                if not role:
                    role = Role(name=role_name)
                role.reset_permissions()
                for permission in roles_permission_map[role_name]:
                    role.add_permission(permission)
                db.session.add(role)
            db.session.commit()
        except:
            db.session.rollback()
        db.session.close()

    def reset_permissions(self):
        self.permissions = 0

    def has_permission(self, permission):
        return self.permissions & permission == permission

    def add_permission(self, permission):
        if not self.has_permission(permission):
            self.permissions += permission

随着应用更新,权限值会不断增加,角色对应的权限值随之增大,为了保证每次更新同步到表,可以在flask应用初始化时添加:

Role.init_role()

这样,我们就赋予了每个角色其拥有的权限值。

重启应用,可以看到role表:

鉴权

前期数据准备妥当了,接下来就是鉴权。

为了保证访问的安全性,需要对接口和权限进行关联绑定,我尝试过两种方案:

1. 装饰器

封装装饰器,对接口视图函数进行装饰,装饰器传入权限值作为参数,在装饰器中根据用户角色的权限和权限值进行对比,判断该用户是否有该接口的访问权限。

刚开始我是用这种方式的,小型应用接口不多的场景下使用还好,但随着应用愈来愈复杂,赋权操作就有点繁琐。

2. 接口赋权

这是我在装饰器之后想到的一种方式,在大型应用接口比较多的情况下比较推荐,而且这种方式耦合度低,易于扩展。

具体操作:首先,将接口地址和权限关联,接口比较多的话,推荐用蓝图,基本上保证一个蓝图中的接口是一个权限,这样操作会简单一些,然后,在应用初始化时将接口地址和权限入库,这样可以保证每次重启应用后数据都是最新的,最后,当用户登录时,会根据用户角色和请求的地址判断其是否有权限访问。

以上两种方式,今天以装饰器鉴权举例说明。

首先,创建鉴权装饰器:

from functools import wraps
from flask import session, abort
from app.models import db, Users, Role

Permission_code = [0X01, 0X02]

def permission_can(current_user, permission):
    """
    检测用户是否有特定权限
    :param current_user
    :param permission
    :return:
    """
    role_id = current_user.role_id
    role = db.session.query(Role).filter_by(id=role_id).first()
    return (role.permissions & permission) == permission

def permission_required(permission):
    """
    权限认证装饰器
    :param permission:
    :return:
    """
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            try:
                current_user = Users.query.filter_by(id=session.get('user_id')).first()

                if not current_user and permission_can(current_user, permission):
                    abort(403)
                return f(*args, **kwargs)
            except:
                abort(403)
        return decorated_function
    return decorator

其中,用到了flask session,获取当前登录用户的user_id,根据当前用户的角色判断其是否拥有该权限permission。

然后在视图函数上添加该装饰器,就可以鉴权了。举例用户管理功能:

@user.route('/user-manage', methods=['POST', 'GET'])
@permission_required(Permissions.USER_MANAGE)
def user_manage():
    """
    用户管理
    :return:
    """
    if request.method == 'POST':
        # 处理...
        ret_data = dict(code=0, ret_msg='user manage')
    else:
        # 数据处理 ...
        ret_data = dict(code=0, ret_msg='user list')
    return jsonify(ret_data)

最后,分别构造请求,访问接口测试:

import requests

session = requests.Session()

# login
login_url = 'http://0.0.0.0:9001/login'
login_data = dict(user='test', pwd='pwd')
login_request = session.post(login_url, json=login_data)
print(login_request.json())

# user_manage
user_manage_url = 'http://0.0.0.0:9001/user-manage'
login_request = session.post(user_manage_url)
print(login_request.json())

# permission_manege
permission_manage_url = 'http://0.0.0.0:9001/permission-manage'
login_request = session.post(permission_manage_url)
print(login_request.json())

具体代码见 my github

以上。

原文地址:https://www.cnblogs.com/ybjourney/p/12387322.html

时间: 2024-10-12 20:37:47

Flask权限管理的相关文章

Oracle 表空间和用户权限管理

一. 表空间 Oracle数据库包含逻辑结构和物理结构. 数据库的物理结构指的是构成数据库的一组操作系统文件. 数据库的逻辑结构是指描述数据组织方式的一组逻辑概念以及它们之间的关系. 表空间是数据库逻辑结构的一个重要组件. 表空间可以存放各种应用对象,如表.索引等. 而每一个表空间由一个或多个数据文件组成. 1. 表空间的分类 表空间可分为3类: 永久性表空间:一般保存表.上天.过程和索引等数据.system.sysaux.users.example表空间是默认安装的. 临时性表空间:只用于保存

linux文件权限管理与ACL访问控制列表

一.文件属性 1.文件属性: 文件属性操作 chown : change owner  ,设置文件所有者 chgrp : change group  ,设置文件的属组 文件属主修改: chown 格式:chown [OPTION]- [OWNER][:[GROUP]] FILE- 用法: OWNER OWNER:GROUPNAME    (同时修改属主.属组) :GROUPNAME                (默认属主,修改属组) ( 命令中的冒号可用.替换:) chown  –refere

mysql的权限管理

mysql的权限管理1.授权的基本原则   只授予满足要求的最小权限,但要注意使用户能够授权给别的用户(with grant option)   对用户设置登录的主机限制   删除没有密码的用户   满足密码的复杂度,设置较为复杂的密码   定期检查用户的权限,适当收回不需要的权限   2.给用户授权  mysql> grant all on *.* to 'root'@'10.0.5.150' identified by 'aixocm';  mysql> flush privileges;

Oracle权限管理详解

转载--CzmMiao的博客生活 Oracle 权限 权限允许用户访问属于其它用户的对象或执行程序,ORACLE系统提供三种权限:Object 对象级.System 系统级.Role 角色级.这些权限可以授予给用户.特殊用户public或角色,如果授予一个权限给特殊用户"Public"(用户public是oracle预定义的,每个用户享有这个用户享有的权限),那么就意味作将该权限授予了该数据库的所有用户.对管理权限而言,角色是一个工具,权限能够被授予给一个角色,角色也能被授予给另一个角

浅析Linux系统下用户与权限管理

Linux作为一种多用户多任务操作系统,在日常的使用中不可避免地要划分出一个角色的概念来管理和使用计算机,这个角色与每一个计算机使用者关联,在Linux中称这种角色为用户.而在每一个用户使用计算机的过程中,又必然存在对有限计算机资源使用的限制性,那么操作系统就必须提供一种途径来保证每个用户独立.合理的使用计算机. 一.用户和用户组管理   (一)用户及用户组相关基本概念  用户:泛指计算机的使用者.用计算机可识别的用户ID(UID,user id)标识. 用户组:用户容器,用来将多个用户合并为一

centos用户权限管理

进程是以其发起者的身份运行的,它对文件的访问权限,取决于此进程的用户的权限.在linux操作系统启动的过程中,为了能够让后台进程或服务类进程以非管理员的身份运行,通常需要为此创建多个普通用户,而这类用户从不需要登录系统,仅让其他进程以他的身份运行,从而仅能获取普通权限的用户.为此这部分用户称系统用户.同时用户与组密不可分.进程的运行是以它的属主(又称,发起者)来访问的.它能访问资源的权限取决于发起者对某个资源的访问权限.下面是从用户和授权两个角度来讲解用户授权管理. 用户管理 用户按类别分管理员

实现业务系统中的用户权限管理--实现篇

在设计篇中,我们已经为大家阐述了有关权限管理系统的数据库设计,在本篇中,我们将重点放在其实现代码部分.为了让你能够更直接更有效的看到全部动作的代码,我们使用"动作分解列表"的方式来陈述每个动作以及相关资源. 实现权限管理功能的动作 动作分解 动作名 相关表名 操作集类型 (S,U,I,D,SQL) 表单 模组 字符资源 是否分页? 返回提示? 权限检测 权限初始化安装 setup 无 无 无 setup setupok 否 否 否 显示添加管理组界面 addnewgroup 无 无 a

RBAC权限管理

RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限. 这样,就构造成“用户-角色-权限”的授权模型.在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系.(如下图) 角色是什么?可以理解为一定数量的权限的集合,权限的载体.例如:一个论坛系统,“超级管理员”.“版主”都是角色.版主可管理版内的帖子.可管理版内的用户等,这些是权限.要给某个用户授予这些权限,不需要直接

Mongodb增加权限管理

 前言: 随着列式存储理念的成熟,越来越多的开发者开始接纳mongodb,hbase这类大储存的分布式列式数据库.特别是mongodb的这种快速搭建,快速使用特点,使其得到更多人的青睐.本人主要通过官网说明针对mongodb权限配置做一个测试与实践. step1:无验证启动mongod服务 mongod --port 27017 --dbpath /data/db1 step2:客户端mongo无密码连接并设置超级用户(用于admin登录) mongo --port 27017 use admi