From d4b49cbb2ba931e85937e098c8f4d681e2343f36 Mon Sep 17 00:00:00 2001 From: wuaho Date: Fri, 14 May 2021 09:46:28 +0800 Subject: [PATCH] =?UTF-8?q?casbin=E5=A4=9A=E7=A7=9F=E6=88=B7=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/api_v1/api.py | 2 +- api/api_v1/endpoints/authority.py | 109 ++++++++++++++------------- api/api_v1/endpoints/dashboard.py | 8 +- api/api_v1/endpoints/project.py | 55 +++++++++++++- api/api_v1/endpoints/table_struct.py | 2 +- api/api_v1/endpoints/user.py | 20 +++-- core/config.py | 7 +- crud/base.py | 22 ++++-- crud/crud_authority.py | 28 ++++--- crud/crud_project.py | 7 +- crud/crud_user.py | 1 + db/init_db.py | 22 +++--- main.py | 2 +- middleware/__init__.py | 1 + middleware/casbin.py | 70 +++++++++++++++++ rbac_model.conf | 8 +- schemas/authotity.py | 3 +- schemas/project.py | 14 ++++ schemas/user.py | 3 + 19 files changed, 275 insertions(+), 109 deletions(-) create mode 100644 middleware/__init__.py create mode 100644 middleware/casbin.py diff --git a/api/api_v1/api.py b/api/api_v1/api.py index 5d276d7..a86a6dd 100644 --- a/api/api_v1/api.py +++ b/api/api_v1/api.py @@ -11,7 +11,7 @@ from .endpoints import query api_router = APIRouter() -api_router.include_router(user.router, tags=["登录接口"], prefix='/user') +api_router.include_router(user.router, tags=["用户接口"], prefix='/user') api_router.include_router(project.router, tags=["项目接口"], prefix='/project') api_router.include_router(folder.router, tags=["文件夹接口"], prefix='/folder') api_router.include_router(space.router, tags=["空间接口"], prefix='/space') diff --git a/api/api_v1/endpoints/authority.py b/api/api_v1/endpoints/authority.py index 4b0449d..fce9f59 100644 --- a/api/api_v1/endpoints/authority.py +++ b/api/api_v1/endpoints/authority.py @@ -13,7 +13,8 @@ router = APIRouter() @router.get("/api_list") -async def api_list(request: Request, current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg: +async def api_list(request: Request, game: str, + current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg: """api 列表""" app = request.app data = [] @@ -25,85 +26,90 @@ async def api_list(request: Request, current_user: schemas.UserDB = Depends(deps @router.post("/add_role") -async def add_role(request: Request, data_in: schemas.CasbinRoleCreate, +async def add_role(request: Request, game: str, data_in: schemas.CasbinRoleCreate, db: AsyncIOMotorDatabase = Depends(get_database), current_user: schemas.UserDB = Depends(deps.get_current_user) ) -> schemas.Msg: """创建角色""" - role = ( - 'g', - 'root', - data_in.role_name, - None - ) - await crud.authority.create(db, role) + role_dom = game + # 角色有的接口权限 + for obj in data_in.role_api: + casbin_enforcer.add_policy(data_in.role_name, role_dom, obj, '*') + await crud.authority.create(db, 'p', data_in.role_name, role_dom, obj, '*') + + # 管理员默认拥有该角色 方便从db中读出 + await crud.authority.create(db, 'g', settings.SUPERUSER_NAME, data_in.role_name, '*', '*', + role_name=data_in.role_name, + game=role_dom) - for item in data_in.role_api: - await crud.authority.create(db, ( - 'p', - data_in.role_name, - item, - '*' - )) return schemas.Msg(code=0, msg='ok') @router.post("/add_account") async def add_account(request: Request, + game: str, data_in: schemas.AccountCreate, db: AsyncIOMotorDatabase = Depends(get_database), current_user: schemas.UserDB = Depends(deps.get_current_user) ) -> schemas.Msg: """创建账号 并设置角色""" - account = schemas.UserCreate(name=data_in.name, password=settings.DEFAULT_PASSWORD) + account = schemas.UserCreate(name=data_in.username, nickname=data_in.nickname, password=settings.DEFAULT_PASSWORD) try: await crud.user.create(db, account) except pymongo.errors.DuplicateKeyError: return schemas.Msg(code=-1, msg='用户名已存在') - rule = ( - 'g', - data_in.name, - data_in.role_name, - None - ) - await crud.authority.create(db, rule) + + casbin_enforcer.add_grouping_policy(data_in.username, data_in.role_name, game) + await crud.authority.create(db, 'g', data_in.username, data_in.role_name, game) return schemas.Msg(code=0, msg='ok') @router.get("/all_role") async def all_role(request: Request, + game: str, db: AsyncIOMotorDatabase = Depends(get_database), current_user: schemas.UserDB = Depends(deps.get_current_user) ) -> schemas.Msg: - """获取所有角色 和 角色权限""" - routes = {} - for item in request.app.routes: - routes[item.path] = item.description if hasattr(item, 'description') else item.name - roles = casbin_enforcer.get_all_roles() - permissions = {} - for role in roles: - for _, path, _ in casbin_enforcer.get_permissions_for_user(role): - permissions.setdefault(role, []) - if path == '*': - permissions[role].clear() + """获取所有角色""" + roles = await crud.authority.find_many(db, role_name={'$exists': 1}, game=game) + data = [{'role': item['v1'], 'name': item['role_name']} for item in roles] + return schemas.Msg(code=0, msg='ok', data=data) - permissions[role] = [{ - 'path': k, - 'name': v - } for k, v in routes.items()] - break - if path in routes: - permissions[role].append( - { - 'path': path, - 'name': routes[path] - } - ) - - return schemas.Msg(code=0, msg='ok', data={'roles': roles, 'permissions': permissions}) +# @router.get("/all_role") +# async def all_role(request: Request, +# db: AsyncIOMotorDatabase = Depends(get_database), +# current_user: schemas.UserDB = Depends(deps.get_current_user) +# ) -> schemas.Msg: +# """获取所有角色 和 角色权限""" +# routes = {} +# for item in request.app.routes: +# routes[item.path] = item.description if hasattr(item, 'description') else item.name +# roles = casbin_enforcer.get_all_roles() +# permissions = {} +# for role in roles: +# for _, path, _ in casbin_enforcer.get_permissions_for_user(role): +# permissions.setdefault(role, []) +# if path == '*': +# permissions[role].clear() +# +# permissions[role] = [{ +# 'path': k, +# 'name': v +# } for k, v in routes.items()] +# break +# +# if path in routes: +# permissions[role].append( +# { +# 'path': path, +# 'name': routes[path] +# } +# ) +# +# return schemas.Msg(code=0, msg='ok', data={'roles': roles, 'permissions': permissions}) @router.post("/set_role") @@ -115,13 +121,10 @@ async def set_role(request: Request, """设置账号角色""" casbin_enforcer.delete_user(data_id.name) casbin_enforcer.add_role_for_user(data_id.name, data_id.role_name) - crud.authority.update_upsert(db, {'prtype': 'g', 'v0': data_id.name}, v1=data_id.role_name) + await crud.authority.update_one(db, {'ptype': 'g', 'v0': data_id.name}, dict(v1=data_id.role_name)) return schemas.Msg(code=0, msg='ok') - - - # @router.get("/delete_user") # async def delete_user(request: Request, # data_id: schemas.AccountDeleteUser, diff --git a/api/api_v1/endpoints/dashboard.py b/api/api_v1/endpoints/dashboard.py index ed02423..b9f0a04 100644 --- a/api/api_v1/endpoints/dashboard.py +++ b/api/api_v1/endpoints/dashboard.py @@ -47,7 +47,8 @@ async def move( """ 移动看板 """ - res = await crud.dashboard.update_one(db, id=data_in.source_id, cat=data_in.cat, pid=data_in.dest_id) + res = await crud.dashboard.update_one(db, {'_id': data_in.source_id}, + {'$set': dict(cat=data_in.cat, pid=data_in.dest_id)}) if res.deleted_count == 0: return schemas.Msg(code=-1, msg='error', data='删除失败') return schemas.Msg(code=0, msg='ok', data='删除成功') @@ -59,7 +60,8 @@ async def add_report(data_in: schemas.AddReport, current_user: schemas.UserDB = Depends(deps.get_current_user) ): """添加报表""" - res = await crud.dashboard.update_one(db, id=data_in.id, **{'$push': {'reports': {'$each': data_in.report_ids}}}) + res = await crud.dashboard.update_one(db, {'_id': data_in.id}, + {'$push': {'reports': {'$each': data_in.report_ids}}}) return schemas.Msg(code=0, msg='ok', data='ok') @@ -70,7 +72,7 @@ async def del_report(data_in: schemas.DelReport, ): """删除报表""" for item in data_in.report_ids: - await crud.dashboard.update_one(db, id=data_in.id, **{'$pull': {'reports': item}}) + await crud.dashboard.update_one(db, {'_id': data_in.id}, {'$pull': {'reports': item}}) return schemas.Msg(code=0, msg='ok', data='ok') diff --git a/api/api_v1/endpoints/project.py b/api/api_v1/endpoints/project.py index 677143f..35d9e8d 100644 --- a/api/api_v1/endpoints/project.py +++ b/api/api_v1/endpoints/project.py @@ -3,9 +3,11 @@ from fastapi import APIRouter, Depends, Request from motor.motor_asyncio import AsyncIOMotorDatabase import crud, schemas from api import deps +from core.config import settings from db import get_database from schemas.project import ProjectCreate +from utils import casbin_enforcer router = APIRouter() @@ -22,8 +24,14 @@ async def create( except pymongo.errors.DuplicateKeyError: return schemas.Msg(code=-1, msg='项目名已存在', data='项目名已存在') # todo 建默认文件夹 - # schemas.FolderCreate - # await crud.folder.create(db, data_in, user_id=current_user.id) + + # 新建项目管理员权限 + role_name = f'{data_in.game}_admin' + role_dom = data_in.game + casbin_enforcer.add_policy(role_name, role_dom, '*', '*') + await crud.authority.create(db, 'p', role_name, role_dom, '*', '*') + # 添加角色 + await crud.authority.create(db, 'g', settings.SUPERUSER_NAME, role_name, '*', '*', role_name='项目管理员', game=role_dom) return schemas.Msg(code=0, msg='创建成功') @@ -38,6 +46,49 @@ async def read_project(request: Request, return schemas.Msg(code=0, msg='ok', data=res) +@router.post("/add_members") +async def add_members(request: Request, + game: str, + data_in: schemas.ProjectMember, + db: AsyncIOMotorDatabase = Depends(get_database), + current_user: schemas.UserDB = Depends(deps.get_current_user) + ): + """项目添加成员""" + + # + # await crud.project.add_members(db, data_in) + for item in data_in.members: + casbin_enforcer.add_grouping_policy(item.username, item.role, game) + await crud.authority.create(db, 'g', item.username, item.role, game) + return schemas.Msg(code=0, msg='ok', data=data_in) + + +@router.get("/members") +async def members(request: Request, + game: str, + db: AsyncIOMotorDatabase = Depends(get_database), + current_user: schemas.UserDB = Depends(deps.get_current_user) + ): + """查看项目成员""" + res = await crud.authority.find_many(db, ptype='g', v2=game) + data = [{'name': 'root', 'role': '超级管理员'}] + data += [{'name': item['v0'], 'role': item['v1']} for item in res] + return schemas.Msg(code=0, msg='ok', data=data) + + +@router.post("/del_member") +async def members(request: Request, + game: str, + data_in: schemas.ProjectDelMember, + db: AsyncIOMotorDatabase = Depends(get_database), + current_user: schemas.UserDB = Depends(deps.get_current_user) + ): + """删除项目成员""" + casbin_enforcer.delete_user(data_in.username) + await crud.authority.delete(db, ptype='g', v2=game, v0=data_in.username) + return schemas.Msg(code=0, msg='ok') + + @router.post("/kanban") async def read_kanban( data_in: schemas.ProjectKanban, diff --git a/api/api_v1/endpoints/table_struct.py b/api/api_v1/endpoints/table_struct.py index fd6cbcc..9b24848 100644 --- a/api/api_v1/endpoints/table_struct.py +++ b/api/api_v1/endpoints/table_struct.py @@ -13,6 +13,7 @@ router = APIRouter() @router.post("/") async def read_table_struct( request: Request, + game: str, data_in: schemas.GetTable, rdb: Redis = Depends(get_redis_pool), current_user: schemas.UserDB = Depends(deps.get_current_user) @@ -20,4 +21,3 @@ async def read_table_struct( """获取表结构""" data = await rdb.get(f'{data_in.game}_{data_in.name}') return schemas.Msg(code=0, msg='ok', data=json.loads(data)) - diff --git a/api/api_v1/endpoints/user.py b/api/api_v1/endpoints/user.py index 245cb7d..3eda3cc 100644 --- a/api/api_v1/endpoints/user.py +++ b/api/api_v1/endpoints/user.py @@ -35,6 +35,7 @@ async def login( return { 'data': { 'name': user.name, + 'nickname': user.nickname, 'email': user.email, 'token': security.create_access_token( expires_delta=access_token_expires, _id=str(user.id), email=user.email, @@ -45,6 +46,7 @@ async def login( }, 'access_token': security.create_access_token( expires_delta=access_token_expires, _id=str(user.id), email=user.email, + nickname=user.nickname, is_superuser=user.is_superuser, name=user.name ), "token_type": "bearer", @@ -62,16 +64,18 @@ def me(current_user: schemas.User = Depends(deps.get_current_user)) -> Any: return current_user -@router.get("/all_user") -async def all_user(db: AsyncIOMotorDatabase = Depends(get_database)) -> Any: +@router.get("/all_account") +async def all_account(page: int = 1, limit: int = 10, db: AsyncIOMotorDatabase = Depends(get_database), + current_user: schemas.User = Depends(deps.get_current_user) + ) -> Any: """ 获取所有用户 """ - users = await crud.user.find_many(db) - data = [{ - "_id": "0", - "name": "所有用户" - }] - data += [schemas.UserDB(**user) for user in users] + page -= 1 + if page < 0: + page = 0 + cursor = crud.user.find(db).skip(page * limit).limit(limit) + + data = [schemas.UserDB(**user) async for user in cursor] return schemas.Msg(code=0, msg='ok', data=data) diff --git a/core/config.py b/core/config.py index 96f124f..40b10dc 100644 --- a/core/config.py +++ b/core/config.py @@ -19,9 +19,10 @@ class Settings(BaseSettings): DATABASE_URI = f'mongodb://{MDB_USER}:{MDB_PASSWORD}@{MDB_HOST}:{MDB_PORT}/admin' - FIRST_EMAIL: str = '15392746632@qq.com' - FIRST_SUPERUSER_PASSWORD: str = '123456' - FIRST_NAME: str = 'root' + SUPERUSER_EMAIL: str = '15392746632@qq.com' + SUPERUSER_PASSWORD: str = '123456' + SUPERUSER_NAME: str = 'root' + SUPERUSER_NICKNAME: str = 'root' DEFAULT_PASSWORD = '123456' diff --git a/crud/base.py b/crud/base.py index eda7ccd..25a01fe 100644 --- a/crud/base.py +++ b/crud/base.py @@ -7,27 +7,33 @@ class CRUDBase: def __init__(self, coll_name): self.coll_name = coll_name - async def get(self, db, id: Union[ObjectId, str]): + async def get(self, db, id: Union[ObjectId, str]) -> dict: return (await db[self.coll_name].find_one({'_id': ObjectId(id)})) or dict() async def read_have(self, db, user_id: str, **kwargs): where = {'members': user_id} where.update(kwargs) cursor = db[self.coll_name].find(where) - return await cursor.to_list(length=999) + return await cursor.to_list(length=9999) async def find_many(self, db, **kwargs): cursor = db[self.coll_name].find(kwargs) - return await cursor.to_list(length=999) + return await cursor.to_list(length=9999) + + def find(self, db, *args, **kwargs): + cursor = db[self.coll_name].find(*args, **kwargs) + return cursor + + @staticmethod + async def to_list(cursor): + async for doc in cursor: + yield doc async def delete(self, db, **kwargs): return await db[self.coll_name].delete_many(kwargs) - async def update_one(self, db, id, **kwargs): - return await db[self.coll_name].update_one({'_id': id}, kwargs) - - async def update_upsert(self, db, where: dict, **kwargs): - return await db[self.coll_name].update_one(where, {'$set': kwargs}, upsert=True) + async def update_one(self, db, filter, update, upsert=False): + return await db[self.coll_name].update_one(filter, update, upsert) async def distinct(self, db, key, filter=None): return await db[self.coll_name].distinct(key, filter) diff --git a/crud/crud_authority.py b/crud/crud_authority.py index 0741644..6f41fc6 100644 --- a/crud/crud_authority.py +++ b/crud/crud_authority.py @@ -11,21 +11,29 @@ __all__ = 'authority', class CRUDAuthority(CRUDBase): - async def create(self, db: AsyncIOMotorDatabase, *args): - casbin_model.add_policy(args[0], args[0], args[1:]) - data = {'ptype': args[0], - 'v0': args[1], - 'v1': args[2], - 'v2': args[3], - } - await self.update_upsert(db, data, **data) + async def create(self, db: AsyncIOMotorDatabase, *args, **kwargs): + data = dict() + if len(args) > 0: + data['ptype'] = args[0] + if len(args) > 1: + data['v0'] = args[1] + if len(args) > 2: + data['v1'] = args[2] + if len(args) > 3: + data['v2'] = args[3] + if len(args) > 4: + data['v3'] = args[4] + if len(args) > 5: + data['v4'] = args[5] + + data.update(kwargs) + await self.update_one(db, data, {'$set': data}, upsert=True) async def create_index(self, db: AsyncIOMotorDatabase): await db[self.coll_name].create_index( [('ptype', pymongo.DESCENDING), ('v0', pymongo.DESCENDING), ('v1', pymongo.DESCENDING), - ('v2', pymongo.DESCENDING)], + ('v2', pymongo.DESCENDING), ('v3', pymongo.DESCENDING)], unique=True) - authority = CRUDAuthority(settings.CASBIN_COLL) diff --git a/crud/crud_project.py b/crud/crud_project.py index 446190d..ed45db7 100644 --- a/crud/crud_project.py +++ b/crud/crud_project.py @@ -13,11 +13,16 @@ class CRUDProject(CRUDBase): **obj_in.dict(), user_id=user_id, members=[user_id], _id=uuid.uuid1().hex ) - 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 read_project(self, db: AsyncIOMotorDatabase, user_id: str): return await self.read_have(db, user_id=user_id) + # async def add_members(self, db: AsyncIOMotorDatabase, obj_in: ProjectMember): + # p = await self.get(db, obj_in.project_id) + # members = list(set(p.get('members')) | set(obj_in.members)) + # await self.update_one(db, {'_id': obj_in.project_id}, {'$set': {'members': members}}) + async def create_index(self, db: AsyncIOMotorDatabase): await db[self.coll_name].create_index('name', unique=True) diff --git a/crud/crud_user.py b/crud/crud_user.py index aab0c5b..36bf20d 100644 --- a/crud/crud_user.py +++ b/crud/crud_user.py @@ -21,6 +21,7 @@ class CRUDUser(CRUDBase): hashed_password=get_password_hash(obj_in.password), name=obj_in.name, is_superuser=obj_in.is_superuser, + nickname=obj_in.nickname, _id=uuid.uuid1().hex ) return await db[self.coll_name].insert_one(db_obj.dict(by_alias=True)) diff --git a/db/init_db.py b/db/init_db.py index 038cd83..35855dc 100644 --- a/db/init_db.py +++ b/db/init_db.py @@ -11,12 +11,13 @@ db = get_database() async def create_superuser(): - user = await crud.user.get_by_user(db=db, name=settings.FIRST_NAME) + user = await crud.user.get_by_user(db=db, name=settings.SUPERUSER_NAME) if not user: user_in = schemas.UserCreate( - name=settings.FIRST_NAME, - email=settings.FIRST_EMAIL, - password=settings.FIRST_SUPERUSER_PASSWORD, + name=settings.SUPERUSER_NAME, + email=settings.SUPERUSER_EMAIL, + password=settings.SUPERUSER_PASSWORD, + nickname=settings.SUPERUSER_NICKNAME, is_superuser=True, ) await crud.user.create(db, user_in) @@ -45,15 +46,10 @@ async def report_index(): async def authority_init(): await crud.authority.create_index(db) - await crud.authority.create(db, 'p', 'admin', '*', '*') - await crud.authority.create(db, 'g', 'root', 'admin', None) - await crud.authority.create(db, 'p', '*', '/docs', '*') - await crud.authority.create(db, 'p', '*', '/openapi.json', '*') - - await crud.authority.create(db, 'p', '*', '/api/v1/user/login', '*') - - await crud.authority.create(db, 'p', '*', '/api/v1/project/', '*') - await crud.authority.create(db, 'p', '*', '/api/v1/project/kanban', '*') + await crud.authority.create(db, 'p', 'anonymous', '*', '/docs', '*') + await crud.authority.create(db, 'p', 'anonymous', '*', '/openapi.json', '*') + await crud.authority.create(db, 'p', 'anonymous', '*', '/api/v1/user/login', '*') + await crud.authority.create(db, 'p', 'anonymous', '*', '/docs', '*') async def main(): diff --git a/main.py b/main.py index 69d145a..ebb16a0 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ from fastapi import FastAPI from starlette.middleware.cors import CORSMiddleware from starlette.authentication import AuthenticationBackend, AuthenticationError, AuthCredentials, BaseUser, SimpleUser from starlette.middleware.authentication import AuthenticationMiddleware -from fastapi_authz import CasbinMiddleware +from middleware import CasbinMiddleware from db import connect_to_mongo, close_mongo_connection, get_database from db.ckdb_utils import connect_to_ck, close_ck_connection diff --git a/middleware/__init__.py b/middleware/__init__.py new file mode 100644 index 0000000..0c3625c --- /dev/null +++ b/middleware/__init__.py @@ -0,0 +1 @@ +from .casbin import CasbinMiddleware \ No newline at end of file diff --git a/middleware/casbin.py b/middleware/casbin.py new file mode 100644 index 0000000..cc1a0da --- /dev/null +++ b/middleware/casbin.py @@ -0,0 +1,70 @@ +from casbin.enforcer import Enforcer +from fastapi import HTTPException +from starlette.authentication import BaseUser +from starlette.requests import Request +from starlette.responses import JSONResponse +from starlette.status import HTTP_403_FORBIDDEN +from starlette.types import ASGIApp, Receive, Scope, Send + +import schemas + + +class CasbinMiddleware: + """ + Middleware for Casbin + """ + + def __init__( + self, + app: ASGIApp, + enforcer: Enforcer, + ) -> None: + """ + Configure Casbin Middleware + + :param app:Retain for ASGI. + :param enforcer:Casbin Enforcer, must be initialized before FastAPI start. + """ + self.app = app + self.enforcer = enforcer + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] not in ("http", "websocket"): + await self.app(scope, receive, send) + return + + if self._enforce(scope, receive): + await self.app(scope, receive, send) + return + else: + response = JSONResponse( + status_code=HTTP_403_FORBIDDEN, + content="没有操作权限" + ) + + await response(scope, receive, send) + return + + def _enforce(self, scope: Scope, receive: Receive) -> bool: + """ + Enforce a request + + :param user: user will be sent to enforcer + :param request: ASGI Request + :return: Enforce Result + """ + + request = Request(scope, receive) + + path = request.url.path + method = request.method + if 'user' not in scope: + raise RuntimeError("Casbin Middleware must work with an Authentication Middleware") + + assert isinstance(request.user, BaseUser) + + user = request.user.display_name if request.user.is_authenticated else 'anonymous' + dom = request.query_params.get('game', '0') + print(user, dom, path, method) + + return self.enforcer.enforce(user, dom, path, method) diff --git a/rbac_model.conf b/rbac_model.conf index 0d4f321..922af8d 100644 --- a/rbac_model.conf +++ b/rbac_model.conf @@ -1,14 +1,14 @@ [request_definition] -r = sub, obj, act +r = sub, dom, obj, act [policy_definition] -p = sub, obj, act +p = sub, dom, obj, act [role_definition] -g = _, _ +g = _, _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] -m = (p.sub == "*" || g(r.sub, p.sub)) && (r.obj == p.obj || keyMatch(r.obj, p.obj)) && (p.act == "*" || r.act == p.act) \ No newline at end of file +m = g(r.sub, p.sub, r.dom) && (p.dom=="*" || r.dom == p.dom) && ( p.obj=="*" || r.obj == p.obj) && (p.act=="*" || r.act == p.act) || r.sub=="root" \ No newline at end of file diff --git a/schemas/authotity.py b/schemas/authotity.py index 86d3856..9fca684 100644 --- a/schemas/authotity.py +++ b/schemas/authotity.py @@ -22,8 +22,9 @@ class CasbinDB(BaseModel): class AccountCreate(BaseModel): - name: str + username: str role_name: str + nickname: str class AccountDeleteUser(BaseModel): diff --git a/schemas/project.py b/schemas/project.py index 069b658..9d3eceb 100644 --- a/schemas/project.py +++ b/schemas/project.py @@ -11,6 +11,20 @@ class ProjectBase(BaseModel): name: str = None +class MemberRole(BaseModel): + username: str + role: str + + +class ProjectMember(BaseModel): + members: List[MemberRole] + # project_id: str + + +class ProjectDelMember(BaseModel): + username: str + + # 解析请求json 创建项目 class ProjectCreate(ProjectBase): name: str = Field(..., title='项目名') diff --git a/schemas/user.py b/schemas/user.py index 0bff6b0..c0a4ea9 100644 --- a/schemas/user.py +++ b/schemas/user.py @@ -9,6 +9,7 @@ class UserBase(BaseModel): email: Optional[EmailStr] = None is_superuser: bool = False name: Optional[str] = None + nickname: str class User(UserBase): @@ -23,6 +24,7 @@ class UserLogin(BaseModel): class UserCreate(UserBase): password: str name: str + nickname: str # **************************************************************************** @@ -33,6 +35,7 @@ class UserDB(DBBase): email: EmailStr = None is_superuser: bool = False name: str + nickname: str class UserDBRW(UserDB):