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 data_auth
from .endpoints import event_mana from .endpoints import event_mana
from .endpoints import test from .endpoints import test
from .authz import authz
api_router = APIRouter() api_router = APIRouter()
api_router.include_router(test.router, tags=["test"], prefix='/test') 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(query.router, tags=["ck"], prefix='/ck')
api_router.include_router(xquery.router, tags=["xck"], 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') 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("/") @router.post("/")
async def dashboards(request: Request, async def dashboards(request: Request,
game: str, game: str,

View File

@ -9,3 +9,5 @@ from .crud_data_auth import data_auth
from .crud_data_attr import data_attr from .crud_data_attr import data_attr
from .crud_api_log import api_log from .crud_api_log import api_log
from .crud_event_mana import event_mana 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 typing import Union
from bson import ObjectId from bson import ObjectId
from motor.motor_asyncio import AsyncIOMotorDatabase
class CRUDBase: class CRUDBase:
@ -38,6 +39,9 @@ class CRUDBase:
async def delete(self, db, filter, collation=None, hint=None, session=None): async def delete(self, db, filter, collation=None, hint=None, session=None):
return await db[self.coll_name].delete_many(filter, collation, hint, session) 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): async def update_one(self, db, filter, update, upsert=False):
res = await db[self.coll_name].update_one(filter, update, upsert) res = await db[self.coll_name].update_one(filter, update, upsert)
return res return res
@ -47,3 +51,6 @@ class CRUDBase:
async def distinct(self, db, key, filter=None): async def distinct(self, db, key, filter=None):
return await db[self.coll_name].distinct(key, filter) 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', __all__ = 'project',
from utils import get_uid
class CRUDProject(CRUDBase): class CRUDProject(CRUDBase):
async def create(self, db: AsyncIOMotorDatabase, obj_in: ProjectCreate, current_user): async def create(self, db: AsyncIOMotorDatabase, obj_in: ProjectCreate, current_user):
db_obj = ProjectDB( db_obj = ProjectDB(
**obj_in.dict(), user_id=current_user.id, members=[current_user.username], **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)) 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): async def read_project(self, db: AsyncIOMotorDatabase, username: str, **kwargs):
return await self.read_have(db, username, **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) 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(): async def authority_init():
await crud.authority.create_index(db) await crud.authority.create_index(db)
await crud.authority.create(db, 'p', '*', '*', '/docs', '*') await crud.authority.create(db, 'p', '*', '*', '/docs', '*')
@ -62,15 +69,17 @@ async def authority_init():
async def main(): async def main():
await create_superuser() # await create_superuser()
await project_index() # await project_index()
await folder_index() # await folder_index()
await space_index() # await space_index()
await dashboard_index() # await dashboard_index()
await report_index() # await report_index()
await authority_init() # await authority_init()
await data_attr_index() # await data_attr_index()
await event_mana() # await event_mana()
await api_list_index()
await role_index()
loop = asyncio.get_event_loop() 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 .sql import *
from .api_log import * from .api_log import *
from .event_mana 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 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): class Ptype(str, Enum):
p = 'p' p = 'p'
g = 'g' g = 'g'

View File

@ -2,7 +2,8 @@ import uuid
from typing import Optional, Union from typing import Optional, Union
from bson import ObjectId from bson import ObjectId
from pydantic import BaseModel, Field from pydantic import BaseModel, Field, validator
from utils import *
# # mongodb _id 类型 # # mongodb _id 类型
@ -21,3 +22,7 @@ from pydantic import BaseModel, Field
class DBBase(BaseModel): class DBBase(BaseModel):
id: str = Field(None, alias='_id') 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 graph_type: str
model: str model: str
graph_size: str graph_size: str
sort: int
class EditShowReport(BaseModel): class EditShowReport(BaseModel):
@ -46,6 +47,11 @@ class Category(str, Enum):
space = 'space' space = 'space'
class EditDashboard(BaseModel):
dashboard_id: str
new_name: str
class DashboardMove(BaseModel): class DashboardMove(BaseModel):
source_ids: List[str] source_ids: List[str]
dest_pid: 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 .adapter import *
from . import casbin from . import casbin
from .func import *

View File

@ -7,7 +7,6 @@ from core.config import settings
__all__ = 'casbin_adapter', 'casbin_enforcer', 'casbin_model' __all__ = 'casbin_adapter', 'casbin_enforcer', 'casbin_model'
class CasbinRule: class CasbinRule:
''' '''
CasbinRule model CasbinRule model
@ -47,6 +46,24 @@ class Adapter(persist.Adapter):
db = client[dbname] db = client[dbname]
self._collection = db[collection] 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): def load_policy(self, model):
''' '''
implementing add Interface for casbin \n implementing add Interface for casbin \n
@ -108,13 +125,15 @@ class Adapter(persist.Adapter):
def remove_policy(self, sec, ptype, rule): def remove_policy(self, sec, ptype, rule):
"""delete policy rules from mongodb""" """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): def remove_filtered_policy(self, sec, ptype, field_index, *field_values):
""" """
delete policy rules for matching filters from mongodb 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) 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 import time
def get_uid(): def get_uid():
return hex(int(time.time() * 10 ** 7))[2:] return hex(int(time.time() * 10 ** 7) + random.randint(0, 10000))[2:]