This commit is contained in:
wuaho 2021-08-05 15:36:09 +08:00
parent 5de25d587e
commit 314fe4d0fa
21 changed files with 431 additions and 148 deletions

View File

@ -12,6 +12,7 @@ from .endpoints import xquery
from .endpoints import data_auth
from .endpoints import event_mana
from .endpoints import test
from .authz import authz
api_router = APIRouter()
api_router.include_router(test.router, tags=["test"], prefix='/test')
@ -31,3 +32,5 @@ api_router.include_router(event_mana.router, tags=["数据管理"], prefix='/dat
api_router.include_router(query.router, tags=["ck"], prefix='/ck')
api_router.include_router(xquery.router, tags=["xck"], prefix='/ck')
api_router.include_router(authz.router, tags=["api接口管理"], prefix='/authz')

View File

181
api/api_v1/authz/authz.py Normal file
View File

@ -0,0 +1,181 @@
from typing import Any
from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase
import crud
import schemas
from api import deps
from db import get_database
from db.ckdb import CKDrive, get_ck_db
from db.redisdb import RedisDrive, get_redis_pool
from models.behavior_analysis import BehaviorAnalysis
from utils import casbin_enforcer
router = APIRouter()
@router.post("/add_role_domain")
async def add_role_domain(
request: Request,
data_in: schemas.AddRoleForUserInDomain,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
在域内为用户添加角色
"""
# username role dom
is_exists_role = await crud.role.check(db, _id=data_in.role_id, game=data_in.game)
if not is_exists_role:
return schemas.Msg(code='-1', msg='角色不存在')
casbin_enforcer.add_role_for_user_in_domain(user=data_in.username,
role=data_in.role_id,
domain=data_in.game)
return schemas.Msg(code='-1', msg='添加成功')
@router.post("/del_role_user_domain")
async def del_role_domain(
request: Request,
data_in: schemas.DeleteRolesForUserInDomain,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
删除用户角色域
"""
# username role dom
res = casbin_enforcer.delete_roles_for_user_in_domain(user=data_in.username,
role=data_in.role_id,
domain=data_in.game)
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/add_policy")
async def add_policy(
request: Request,
data_id: schemas.AddPolicy,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
向当前策略添加授权规则
"""
res = casbin_enforcer.add_policy(data_id.role_id, data_id.game, data_id.path, data_id.act)
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/del_policy")
async def remove_policy(
request: Request,
data_id: schemas.DelPolicy,
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
向当前策略添加授权规则
"""
res = casbin_enforcer.remove_policy(data_id.role_id, data_id.game, data_id.path, data_id.act)
return schemas.Msg(code=0, msg='ok', data=res)
@router.get("/api_list")
async def api_list(
request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)):
"""
GetPermissionsForUserInDomain
已经添加的api
标记 已添加的权限
"""
res = await crud.api_list.all_api(db, game)
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/add_api")
async def add_api(
request: Request,
data_in: schemas.AddApi,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
添加api
"""
res = await crud.api_list.add_api(db, data_in)
return schemas.Msg(code=0, msg='ok', data=res.matched_count)
@router.post("/del_api")
async def del_api(
request: Request,
data_in: schemas.DelApi,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""
删除api
"""
res = await crud.api_list.del_api(db, data_in)
return schemas.Msg(code=0, msg='ok', data=res.deleted_count)
@router.post("/edit_api")
async def edit_api(
request: Request,
data_in: schemas.EditApi,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
"""
编辑api
"""
res = await crud.api_list.edit_api(db, data_in)
return schemas.Msg(code=0, msg='ok', data=res.deleted_count)
@router.get("/domain")
async def domain_list(
request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
可选择域 游戏代号
"""
# roel dom path *
res = await crud.project.all_game(db)
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/add_roles")
async def add_roles(
request: Request,
data_in: schemas.AddRole,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
新建角色
"""
try:
res = await crud.role.add_role(db, data_in)
return schemas.Msg(code=0, msg='ok', data=res.matched_count)
except Exception as e:
return schemas.Msg(code=-1, msg='添加失败', data=str(e))
@router.get("/roles")
async def roles(
request: Request,
game: str,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""
域内所有角色
"""
res = await crud.role.dom_roles(db, game)
return schemas.Msg(code=0, msg='ok', data=res)

View File

@ -143,6 +143,18 @@ async def del_report(
return schemas.Msg(code=0, msg='ok', data='ok')
@router.post("/edit")
async def edit(
game: str,
data_in: schemas.EditDashboard,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""编辑看板名"""
await crud.dashboard.update_one(db, {'_id': data_in.dashboard_id}, {'$set': {'name': data_in.new_name}})
return schemas.Msg(code=0, msg='ok', data='ok')
@router.post("/")
async def dashboards(request: Request,
game: str,

View File

@ -9,3 +9,5 @@ from .crud_data_auth import data_auth
from .crud_data_attr import data_attr
from .crud_api_log import api_log
from .crud_event_mana import event_mana
from .crud_api_list import api_list
from .crud_role import role

View File

@ -1,6 +1,7 @@
from typing import Union
from bson import ObjectId
from motor.motor_asyncio import AsyncIOMotorDatabase
class CRUDBase:
@ -38,6 +39,9 @@ class CRUDBase:
async def delete(self, db, filter, collation=None, hint=None, session=None):
return await db[self.coll_name].delete_many(filter, collation, hint, session)
async def delete_id(self, db, *args):
return await db[self.coll_name].delete_one({'_id': {'$in': list(args)}})
async def update_one(self, db, filter, update, upsert=False):
res = await db[self.coll_name].update_one(filter, update, upsert)
return res
@ -47,3 +51,6 @@ class CRUDBase:
async def distinct(self, db, key, filter=None):
return await db[self.coll_name].distinct(key, filter)
# async def _create_index(self, db: AsyncIOMotorDatabase, *args, **kwargs):
# return await db[self.coll_name].create_index(*args, **kwargs)

38
crud/crud_api_list.py Normal file
View File

@ -0,0 +1,38 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'api_list',
class CRUDApiList(CRUDBase):
async def add_api(self, db: AsyncIOMotorDatabase, data_in: schemas.AddApi):
where = {'path': data_in.path}
data = {'$set': schemas.AddApiDB(**data_in.dict()).dict(by_alias=True)}
return await self.update_one(db, where, data, upsert=True)
async def edit_api(self, db: AsyncIOMotorDatabase, data_in: schemas.EditApi):
where = {'_id': data_in.id}
data = {'$set': data_in.dict()}
return await self.update_one(db, where, data)
async def all_api(self, db: AsyncIOMotorDatabase, game):
where = {'game': game}
return await self.find_many(db, where)
async def del_api(self, db: AsyncIOMotorDatabase, data_in: schemas.DelApi):
return await self.delete_id(db, *data_in.ids)
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index('path', unique=True)
api_list = CRUDApiList('api_list')

View File

@ -5,16 +5,21 @@ from schemas import *
__all__ = 'project',
from utils import get_uid
class CRUDProject(CRUDBase):
async def create(self, db: AsyncIOMotorDatabase, obj_in: ProjectCreate, current_user):
db_obj = ProjectDB(
**obj_in.dict(), user_id=current_user.id, members=[current_user.username],
_id=uuid.uuid1().hex
_id=get_uid()
)
return await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
async def all_game(self, db: AsyncIOMotorDatabase):
return await self.find_many(db, {}, {'game': True, 'name': True, '_id': False})
async def read_project(self, db: AsyncIOMotorDatabase, username: str, **kwargs):
return await self.read_have(db, username, **kwargs)

37
crud/crud_role.py Normal file
View File

@ -0,0 +1,37 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'role',
class CRUDApiList(CRUDBase):
async def add_role(self, db: AsyncIOMotorDatabase, data_in: schemas.AddRole):
where = {'name': data_in.name, 'game': data_in.game}
data = {'$set': schemas.AddRoleDB(**data_in.dict()).dict(by_alias=True)}
return await self.update_one(db, where, data, upsert=True)
async def edit_role(self, db: AsyncIOMotorDatabase, data_in: schemas.EditRole):
where = {'_id': data_in.id}
data = {'$set': data_in.dict()}
return await self.update_one(db, where, data)
async def check(self, db, **kwargs):
res = await self.find_one(db, kwargs)
return True if res else False
async def dom_roles(self, db: AsyncIOMotorDatabase, game: str):
where = {'game': game}
return await self.find_many(db, where)
async def del_role(self, db: AsyncIOMotorDatabase, data_in: schemas.DelRole):
return await self.delete_id(db, *data_in.ids)
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index([('game', 1), ('name', 1)], unique=True)
role = CRUDApiList('role')

View File

@ -52,6 +52,13 @@ async def event_mana():
await crud.event_mana.create_index(db)
async def api_list_index():
await crud.api_list.create_index(db)
async def role_index():
await crud.role.create_index(db)
async def authority_init():
await crud.authority.create_index(db)
await crud.authority.create(db, 'p', '*', '*', '/docs', '*')
@ -62,15 +69,17 @@ async def authority_init():
async def main():
await create_superuser()
await project_index()
await folder_index()
await space_index()
await dashboard_index()
await report_index()
await authority_init()
await data_attr_index()
await event_mana()
# await create_superuser()
# await project_index()
# await folder_index()
# await space_index()
# await dashboard_index()
# await report_index()
# await authority_init()
# await data_attr_index()
# await event_mana()
await api_list_index()
await role_index()
loop = asyncio.get_event_loop()

View File

@ -1,22 +0,0 @@
import logging
from db.init_db import init_db
from db.mongodb_utils import SessionLocal
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def init() -> None:
db = SessionLocal()
init_db(db)
def main() -> None:
logger.info("Creating initial data")
init()
logger.info("Initial data created")
if __name__ == "__main__":
main()

View File

@ -12,4 +12,6 @@ from .data_attr import *
from .sql import *
from .api_log import *
from .event_mana import *
from .xquery import *
from .xquery import *
from .api_list import *
from .role import *

33
schemas/api_list.py Normal file
View File

@ -0,0 +1,33 @@
from typing import Any, List, Union
from pydantic import BaseModel, Field
from schemas import DBBase
from typing import Optional
class ApiBase(BaseModel):
path: str = None
name: str = None
desc: str = None
class AddApi(ApiBase):
path: str
name: str
desc: str
class AddApiDB(DBBase, AddApi):
pass
class DelApi(BaseModel):
ids: List[str] = Field(..., description='要删除的id')
class EditApi(ApiBase):
id: str = Field(..., description='要编辑的id')

View File

@ -4,6 +4,31 @@ from typing import List
from pydantic import BaseModel
class AddRoleForUserInDomain(BaseModel):
username: str
role_id: str
game: str
class DeleteRolesForUserInDomain(BaseModel):
username: str
role_id: str
game: str
class Policy(BaseModel):
role_id: str
game: str
path: str
act: str = '*'
class AddPolicy(Policy):
pass
class DelPolicy(Policy):
pass
class Ptype(str, Enum):
p = 'p'
g = 'g'

View File

@ -2,7 +2,8 @@ import uuid
from typing import Optional, Union
from bson import ObjectId
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, validator
from utils import *
# # mongodb _id 类型
@ -21,3 +22,7 @@ from pydantic import BaseModel, Field
class DBBase(BaseModel):
id: str = Field(None, alias='_id')
@validator('id', pre=True, always=True)
def default_id(cls, v):
return v or get_uid()

View File

@ -34,6 +34,7 @@ class Report(BaseModel):
graph_type: str
model: str
graph_size: str
sort: int
class EditShowReport(BaseModel):
@ -46,6 +47,11 @@ class Category(str, Enum):
space = 'space'
class EditDashboard(BaseModel):
dashboard_id: str
new_name: str
class DashboardMove(BaseModel):
source_ids: List[str]
dest_pid: str

29
schemas/role.py Normal file
View File

@ -0,0 +1,29 @@
from typing import List
from pydantic import Field
from pydantic.main import BaseModel
from schemas import DBBase
class RoleBase(BaseModel):
game: str = None
name: str = None
desc: str = None
class AddRole(BaseModel):
game: str
name: str
desc: str
class AddRoleDB(DBBase, AddRole):
pass
class DelRole(BaseModel):
ids: List[str] = Field(..., description='要删除的id')
class EditRole(RoleBase):
id: str = Field(..., description='要编辑的id')

View File

@ -1,3 +1,4 @@
from .adapter import *
from . import casbin
from .func import *

View File

@ -7,7 +7,6 @@ from core.config import settings
__all__ = 'casbin_adapter', 'casbin_enforcer', 'casbin_model'
class CasbinRule:
'''
CasbinRule model
@ -47,6 +46,24 @@ class Adapter(persist.Adapter):
db = client[dbname]
self._collection = db[collection]
@staticmethod
def format_policy(ptype, args):
line = CasbinRule(ptype=ptype)
if len(args) > 0:
line.v0 = args[0]
if len(args) > 1:
line.v1 = args[1]
if len(args) > 2:
line.v2 = args[2]
if len(args) > 3:
line.v3 = args[3]
if len(args) > 4:
line.v4 = args[4]
if len(args) > 5:
line.v5 = args[5]
return line
def load_policy(self, model):
'''
implementing add Interface for casbin \n
@ -108,13 +125,15 @@ class Adapter(persist.Adapter):
def remove_policy(self, sec, ptype, rule):
"""delete policy rules from mongodb"""
pass
line = self.format_policy(ptype, rule)
self._collection.delete_one(line.dict())
def remove_filtered_policy(self, sec, ptype, field_index, *field_values):
"""
delete policy rules for matching filters from mongodb
"""
pass
line = self.format_policy(ptype, field_values)
self._collection.delete_one(line.dict())
casbin_adapter = Adapter(settings.DATABASE_URI, settings.MDB_DB)

View File

@ -1,110 +0,0 @@
from .casbin import persist
class CasbinRule:
'''
CasbinRule model
'''
def __init__(self, ptype = None, v0 = None, v1 = None, v2 = None, v3 = None, v4 = None, v5 = None):
self.ptype = ptype
self.v0 = v0
self.v1 = v1
self.v2 = v2
self.v3 = v3
self.v4 = v4
self.v5 = v5
def dict(self):
d = {'ptype': self.ptype}
for i, v in enumerate([self.v0, self.v1, self.v2, self.v3, self.v4, self.v5]):
if v is None:
break
d['v' + str(i)] = v
return d
def __str__(self):
return ', '.join(self.dict().values())
def __repr__(self):
return '<CasbinRule :"{}">'.format(str(self))
class Adapter(persist.Adapter):
"""the interface for Casbin adapters."""
def __init__(self,db, collection="casbin_rule"):
self._collection = db[collection]
async def load_policy(self, model):
'''
implementing add Interface for casbin \n
load all policy rules from mongodb \n
'''
async for line in self._collection.find():
if 'ptype' not in line:
continue
rule = CasbinRule(line['ptype'])
if 'v0' in line:
rule.v0 = line['v0']
if 'v1' in line:
rule.v1 = line['v1']
if 'v2' in line:
rule.v2 = line['v2']
if 'v3' in line:
rule.v3 = line['v3']
if 'v4' in line:
rule.v4 = line['v4']
if 'v5' in line:
rule.v5 = line['v5']
persist.load_policy_line(str(rule), model)
async def _save_policy_line(self, ptype, rule):
line = CasbinRule(ptype=ptype)
if len(rule) > 0:
line.v0 = rule[0]
if len(rule) > 1:
line.v1 = rule[1]
if len(rule) > 2:
line.v2 = rule[2]
if len(rule) > 3:
line.v3 = rule[3]
if len(rule) > 4:
line.v4 = rule[4]
if len(rule) > 5:
line.v5 = rule[5]
await self._collection.insert_one(line.dict())
async 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:
await self._save_policy_line(ptype, rule)
return True
async def add_policy(self, sec, ptype, rule):
"""add policy rules to mongodb"""
await 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

View File

@ -1,5 +1,6 @@
import random
import time
def get_uid():
return hex(int(time.time() * 10 ** 7))[2:]
return hex(int(time.time() * 10 ** 7) + random.randint(0, 10000))[2:]