Merge commit '47296980495f8bbfc9493e93de85dd62de6fa6b9' as 'paste-framework'
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
import importlib
|
||||
|
||||
from sqlalchemy import delete
|
||||
|
||||
from paste.core import config
|
||||
from paste.rbac.rbac_item import RbacItem
|
||||
from paste.web.application import Application
|
||||
|
||||
|
||||
class RbacPermission(RbacItem):
|
||||
"""
|
||||
权限。
|
||||
大多数情况下,权限都对应着一个具体的请求操作,且经由导入期自动导入。
|
||||
权限的 name 属性为请求控制器 RequestHandler 的 route_pattern 属性值,
|
||||
权限的 description 属性对应于 RequestHandler 类的文档注释的第一行。
|
||||
权限可以分配给用户,也可以分配给角色或其他权限。
|
||||
|
||||
此外允许手动创建权限,主要是为规则创建一个权限载体,当其他的权限属于这个权限的子权限时,相当于同时拥有了这个权限的规则。
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
async def create(cls, name: str, description: str = None, rule_name: str = None):
|
||||
"""
|
||||
创建权限。
|
||||
|
||||
:param name: 权限名称
|
||||
:param rule_name: 规则名称
|
||||
:param description: 权限描述
|
||||
:return: 权限对象
|
||||
"""
|
||||
assert name not in ('', None), '必须提供权限名称.'
|
||||
_permission = cls(name=name, description=description, type=cls.TYPE_PERMISSION)
|
||||
_permission.rule_name = rule_name if rule_name else _permission.rule_name
|
||||
await _permission.async_save()
|
||||
return _permission
|
||||
|
||||
@classmethod
|
||||
async def delete(cls, name: str):
|
||||
"""
|
||||
删除权限。
|
||||
|
||||
:param name: 授权项名称
|
||||
:return: 操作状态,游标返回对象
|
||||
"""
|
||||
assert name not in ('', None), '必须提供权限名称.'
|
||||
_query = delete(cls).where(cls.name == name)
|
||||
_result = await cls.raw_execute(query=_query)
|
||||
_rowcount = _result.rowcount if isinstance(_result.rowcount, int) else 0
|
||||
return _rowcount > 0, _result
|
||||
|
||||
@classmethod
|
||||
async def modify(cls, name: str, description: str = None, rule_name: str = None):
|
||||
"""
|
||||
编辑权限。
|
||||
|
||||
:param name: 名称
|
||||
:param description: 描述
|
||||
:param rule_name: 规则名称
|
||||
:return: 权限对象
|
||||
"""
|
||||
assert name not in ('', None), '必须提供权限名称.'
|
||||
_permission: cls = await cls(name=name).async_find_first()
|
||||
assert _permission, f"未找到名称为:{name} 的权限."
|
||||
|
||||
_permission.description = description if description else _permission.description
|
||||
_permission.rule_name = rule_name if rule_name else _permission.rule_name
|
||||
await _permission.async_save()
|
||||
return _permission
|
||||
|
||||
@classmethod
|
||||
def identify_permission(cls):
|
||||
"""
|
||||
根据应用程序配置,从应用程序目录中识别所有的控制器,及其对应的路由。
|
||||
读取配置文件中关于 tornado 部分的配置,扫描配置包中的所有 Handler 类。
|
||||
识别需要授权的接口,即包含 auth_permission 装饰器的接口。
|
||||
忽略无需授权的接口,如:部分 OpenAPI 或 FrontendAPI。
|
||||
|
||||
:return: 识别到的控制器列表,注意列表中是 tuple(route, handler_type)
|
||||
"""
|
||||
apps_config: dict = config.get_config('tornado')
|
||||
_handlers: list[tuple[str, type]] = []
|
||||
|
||||
for _n, _app_cfgs in apps_config.items():
|
||||
for app_cfg in _app_cfgs:
|
||||
_handlers_pkg = app_cfg.get('handlers_pkg')
|
||||
_modules_itr = Application.modules_iterator(package=_handlers_pkg)
|
||||
for file_finder, handler_name, is_package in _modules_itr:
|
||||
if is_package:
|
||||
continue
|
||||
|
||||
_module = importlib.import_module(handler_name)
|
||||
_hls_list = Application.fetch_handlers(module=_module)
|
||||
for _hls in _hls_list:
|
||||
_uri, _hdl = _hls
|
||||
# 检查 post 或 get 是否被 auth_permission 装饰
|
||||
for method_name in ['post', 'get']:
|
||||
method = getattr(_hdl, method_name, None)
|
||||
if method and callable(method):
|
||||
if getattr(method, '__auth_permission__', False):
|
||||
_handlers.append(_hls)
|
||||
break
|
||||
|
||||
return _handlers
|
||||
|
||||
@classmethod
|
||||
async def import_permissions(cls):
|
||||
"""
|
||||
导入所有的可分配权限到数据库,若已经在数据库存在,则更新。
|
||||
"""
|
||||
_handlers = cls.identify_permission()
|
||||
|
||||
# 根据所有的路由信息,查出已经有的权限数据
|
||||
_routes: list[str] = [rc[0] for rc in _handlers]
|
||||
_item_model_list: list[cls] = await cls(**{cls.name.key: _routes}).async_find()
|
||||
|
||||
# 利用路由 Key 建立索引
|
||||
_item_model_dict: dict[str: cls] = {_item.name: _item for _item in _item_model_list}
|
||||
|
||||
_permissions: list[cls] = []
|
||||
for _route, _cls in _handlers:
|
||||
# 取得类描述
|
||||
_desc = f"{_cls.__doc__}".strip().split('\n')[0].strip(),
|
||||
# 利用路由取出模型
|
||||
_perm_item: cls = _item_model_dict.get(_route, None)
|
||||
if _perm_item is None:
|
||||
# 未得到模型,创建
|
||||
_perm_item = cls(**{cls.name.key: _route, cls.description.key: _desc})
|
||||
else:
|
||||
# 已得到模型,更新
|
||||
_perm_item.description = _desc
|
||||
_perm_item.close_session()
|
||||
|
||||
# 加入列表,批量保存
|
||||
_permissions.append(_perm_item)
|
||||
|
||||
# 保存数据
|
||||
_session = cls.get_aio_session()
|
||||
try:
|
||||
_session.add_all(_permissions)
|
||||
await _session.commit()
|
||||
except Exception as e:
|
||||
await _session.rollback()
|
||||
raise e
|
||||
finally:
|
||||
await _session.close()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.type = self.TYPE_PERMISSION
|
||||
Reference in New Issue
Block a user