权限管理(1/3):pyCasbin 持久化,基于json文件adapter 实现方法

PyCasbin: 支持 ACL、RBAC、ABAC 多种模型的 Python 权限管理框架

PyCasbin 是一个用 Python 语言打造的轻量级开源访问控制框架( https://github.com/casbin/pycasbin ),目前在 GitHub 开源。PyCasbin 采用了元模型的设计思想,支持多种经典的访问控制方案,如基于角色的访问控制 RBAC、基于属性的访问控制 ABAC 等。

PyCasbin 的主要特性包括

1.支持自定义请求的格式,默认的请求格式为{subject, object, action};

2.具有访问控制模型 model 和策略 policy 两个核心概念;

3.支持 RBAC 中的多层角色继承,不止主体可以有角色,资源也可以具有角色;

4.支持超级用户,如 root 或 Administrator,超级用户可以不受授权策略的约束访问任意资源;

5.支持多种内置的操作符,如 keyMatch,方便对路径式的资源进行管理,如 /foo/bar 可以映射到 /foo*

PyCasbin 不做的事情:

1.身份认证 authentication (即验证用户的用户名、密码),PyCasbin 只负责访问控制。应该有其他专门的组件负责身份认证,然后由 PyCasbin 进行访问控制,二者是相互配合的关系;

2.管理用户列表或角色列表。PyCasbin 认为由项目自身来管理用户、角色列表更为合适,PyCasbin 假设所有策略和请求中出现的用户、角色、资源都是合法有效的。

安装

pip install casbin

HelloWorld 例子

1.初始化一个 enforcer,传入两个参数:模型文件路径和策略文件路径;

import casbin
e = casbin.Enforcer("path/to/model.conf", "path/to/policy.csv")

2.在你的代码需要进行访问控制的位置,加入如下钩子;

sub = "alice"  # the user that wants to access a resource.
obj = "data1"  # the resource that is going to be accessed.
act = "read"  # the operation that the user performs on the resource.

if e.enforce(sub, obj, act):
    # permit alice to read data1
    pass
else:
    # deny the request, show an error
    pass

3.采用管理 API 进行权限的管理,如获取一个用户所有的角色;

roles = e.get_roles("alice")

社区进展

PyCasbin 目前正在积极向社区进行推送,并且可以通过插件的方式已经支持与 Django 等 Web 框架进行集成,将来会推广到更多 Web 框架以及社区。Casbin 已经有 Golang 版本、Java 版本、PHP 版本、Node.js 版本、Pytho n版本 等主流语言版本。有跨语言需求的开发者可以只用 Casbin 这一套框架就实现多个不同语言的项目的权限管理任务。

  • PyCasbin (Python): https://github.com/casbin/pycasbin
  • Casbin (Go): https://github.com/casbin/casbin
  • jCasbin (Java): https://github.com/casbin/jcasbin
  • PHP-Casbin (PHP): https://github.com/php-casbin/php-casbin
  • Node-Casbin (Node.js): https://github.com/casbin/node-casbin

协议

PyCasbin 采用 Apache 2.0 开源协议发布。


权限管理开源库pyCasbin 持久化 基于json文件adapter 实现方法

前言
公司的软件管理一直没有权限管理模块,最近老板让研究一下Casbin 这个开源库,花了两天简单的了解了一下,由于Casbin没有c/c++版本实现,而我会一点python 语法,所以选择研究一下python 版本pyCasbin的使用

PyCasbin 是一个用 Python 语言打造的轻量级开源访问控制框架目前GitHub(https://github.com/casbin/pycasbin)开源。PyCasbin 采用了元模型的设计思想,支持多种经典的访问控制方案,如基于角色的访问控制 RBAC、基于属性的访问控制 ABAC 等。
主要特性:
1.支持自定义请求的格式,默认的请求格式为{subject, object, action};
2.具有访问控制模型 model 和策略 policy 两个核心概念;
3.支持 RBAC 中的多层角色继承,不止主体可以有角色,资源也可以具有角色;
4.支持超级用户,如 root 或 Administrator,超级用户可以不受授权策略的约束访问任意资源;
5.支持多种内置的操作符,如 keyMatch,方便对路径式的资源进行管理,如 /foo/bar 可以映射到 /foo*

1.安装和使用测试
英文ok 可以官网https://python.ctolib.com/casbin-pycasbin.html 了解一下,或者找个博客https://blog.csdn.net/byywcsnd/article/details/86644190了解一下,安装使用测试还是比较简单的,熟悉python的同学按照文章中的步骤做就行了

2.关于持久化
按照上面链接的文章使用会发现如果调用pycasbin 接口增加删除policy然后保存policy(有自动保存选项),下次再次调用,之前增加或者删除的policy效果无效,查看原来导入 policy对应的文件内容没有变化,查看官方文档发现原来为了保持casbin库的轻量级和灵活性,持久化(保存功能)只提供了虚接口,具体实现需要安装或者自己实现对应的adapter

3.adapter的作用和实现方法
adapter的最主要作用
1.提供把文件或者数据库中的policy信息读取解析导入casbin 中的policy的方法
2.提供把casbin中的policy 存入文件或者数据库中的方法
所以自己实现的adapter只要实现有这两个功能的就行了
class MAdapter(persist.Adapter): #定义一个python 类 MAdapter继承 persist.Adapter这个类,我们看着这个类

    `class Adapter:
"""the interface for Casbin adapters."""
def load_policy(self, model):
    """loads all policy rules from the storage."""
    pass
def save_policy(self, model):
    """saves all policy rules to the storage."""
    pass
def add_policy(self, sec, ptype, rule):
    """adds a policy rule to the storage."""
    pass
def remove_policy(self, sec, ptype, rule):
    """removes a policy rule from the storage."""
    pass`

可以看出这个基类有方法load_policy,和save_policy,对应上面这个adapter最主要的两个作用,我们按照要求重写这两个方法就行了

由于我的python语法和一些常见的python方法使用不熟练所以做了一个简单的基于json文件的adapter(demon级别只少没有错误异常检测 当policy信息量大的时候保存性能没有考虑),就当抛转作用,大家可以简单参考下写出基于其它的各种文件类型和数据库类型的adapter

4.代码实现和测试

自己写的adapter文件mJsonAdapter.py

import casbin
import json
import os
from casbin import persist

class CasbinRule(object):
    #PType=''
    #v0=''
    #v1=''
    #v2=''
    #v3=''
    #v4=''
    #v5=''
    __tablename__ = "casbin_rule"
    def __init__(self,PType_='',v0_='',
                 v1_='',v2_='',v3_='',
                 v4_='',v5_=''):
        self.PType=PType_
        self.v0=v0_
        self.v1=v1_
        self.v2=v2_
        self.v3=v3_
        self.v4=v4_
        self.v5=v5_

    def load(self):
        text = self.PType
        if self.v0!='':
            text = text+', '+self.v0
        if self.v1!='':
            text = text+', '+self.v1
        if self.v2!='':
            text = text+', '+self.v2
        if self.v3!='':
            text = text+', '+self.v3
        if self.v4!='':
            text = text+', '+self.v4
        if self.v5!='':
            text = text+', '+self.v5
        return text

    def __repr__(self):
        return ''.format(str(self))

class MAdapter(persist.Adapter):

    pfpath='none.json'
    storeJs=json.loads("{}")
    def __init__(self,  policyFilePath):
        self.pfpath=policyFilePath
        
    def load_policy(self, model):
        fd=open(self.pfpath,mode='r')
        str=fd.read()
        fd.close()
        #print (str)
        self.storeJs=json.loads(str)

        casbinRuleStrct = []
        for item in self.storeJs:
            cr=CasbinRule(item['PType'],
                          item['V0'],item['V1'],
                          '','',
                          '', '')
            if item.get('V2'):
                cr.v2=item['V2']
            if item.get('V3'):
                cr.v2=item['V3']
            if item.get('V4'):
                cr.v2=item['V4']
            if item.get('V5'):
                cr.v2 = item['V5']
            print (cr.load())
            persist.load_policy_line(cr.load(),model)

    def _save_policy_line(self, ptype, rule):
        csbr = CasbinRule()
        csbr.PType=ptype
        if len(rule) > 0:
            csbr.v0 = rule[0]
        if len(rule) > 1:
            csbr.v1 = rule[1]
        if len(rule) > 2:
            csbr.v2 = rule[2]
        if len(rule) > 3:
            csbr.v3 = rule[3]
        if len(rule) > 4:
            csbr.v4 = rule[4]
        if len(rule) > 5:
            csbr.v5 = rule[5]
        self.saveCasbinRule(csbr)
    def saveCasbinRule(self,casbinRule):
        if(casbinRule.PType==''):
            return False
        js=json.loads("{}")
        js["PType"]=casbinRule.PType
        if(casbinRule.v0!=''):
            js['V0']=casbinRule.v0
        if(casbinRule.v1!=''):
            js['V1']=casbinRule.v1
        if(casbinRule.v2!=''):
            js['V2']=casbinRule.v2
        if(casbinRule.v3!=''):
            js['V3']=casbinRule.v3
        if(casbinRule.v4!=''):
            js['V4']=casbinRule.v4
        if(casbinRule.v5!=''):
            js['V5']=casbinRule.v5
        flag = 0
        for item in self.storeJs:
            if (item==js):
                flag=1
                break
        if (flag==0):
            self.storeJs.append(js)


    def save_policy(self, model):
        '''
        implementing add Interface for casbin \n
        save the policy in mongodb \n
        '''
        for sec in ["p", "g"]:
            if sec not in model.model.keys():
                continue
            for ptype, ast in model.model[sec].items():
                for rule in ast.policy:
                    self._save_policy_line(ptype, rule)
        fd = open(self.pfpath, mode='w+')
        fd.write(json.dumps(self.storeJs))
        print (json.dumps(self.storeJs))
        fd.close()
        return True

    def add_policy(self, sec, ptype, rule):
        """add policy rules to mongodb"""
        self._save_policy_line(ptype, rule)

    def remove_policy(self, sec, ptype, rule):
        """delete policy rules from mongodb"""
        pass

    def remove_filtered_policy(self, sec, ptype, field_index, *field_values):
        """
        delete policy rules for matching filters from mongodb
        """
        pass


model配置文件    rbac_model.conf
1
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act


policy导入和保存的文件 rbac_policy.json

[{"PType": "p", "V0": "alice", "V1": "data1", "V2": "read"}, 
    {"PType": "p", "V0": "bob", "V1": "data2", "V2": "write"},
     {"PType": "p", "V0": "data2_admin", "V1": "data2", "V2": "read"}, 
     {"PType": "p", "V0": "data2_admin", "V1": "data2", "V2": "write"},
      {"PType": "g", "V0": "alice", "V1": "data2_admin"}, 
 {"PType": "p", "V0": "alice", "V1": "data2", "V2": "write"}]


测试代码文件 jsonAdapterTest.py

import casbin
import mJsonAdapter

from  mJsonAdapter import  MAdapter        

adapter=MAdapter('rbac_policy.json') 

e=casbin.Enforcer('rbac_model.conf',adapter,True)

f=e.enforce('ywh','data','read')
e.add_policy('ywh','data','read') #'ywh','data','write'
e.save_policy()
if f:
    print ("true")
else:
    print ("false")


测试方法很简单,因为配置文件中刚开始没有 ‘ywh’,‘data’,'read’这个policy信息,第一次执行打印是false,关闭程序再次执行会发现打印true,同时会发现文件rbac_policy.json内容改变了.
已经通过本人测试,基于json文件adapter 已经简单实现,这只是一个简单版本,提供一下casbin的adapter的实现思路

    [参考](https://python.ctolib.com/casbin-pycasbin.html)
    [参考](https://casbin.org/docs/en/adapters)
    [参考](https://blog.csdn.net/byywcsnd/article/details/86644190)


你可能感兴趣的:(权限管理(1/3):pyCasbin 持久化,基于json文件adapter 实现方法)