1
This commit is contained in:
parent
2fb9b4573c
commit
224d9816fa
@ -5,6 +5,7 @@ from .endpoints import folder
|
|||||||
from .endpoints import space
|
from .endpoints import space
|
||||||
from .endpoints import dashboard
|
from .endpoints import dashboard
|
||||||
from .endpoints import report
|
from .endpoints import report
|
||||||
|
from .endpoints import authority
|
||||||
|
|
||||||
api_router = APIRouter()
|
api_router = APIRouter()
|
||||||
|
|
||||||
@ -14,3 +15,5 @@ api_router.include_router(folder.router, tags=["文件夹接口"], prefix='/fold
|
|||||||
api_router.include_router(space.router, tags=["空间接口"], prefix='/space')
|
api_router.include_router(space.router, tags=["空间接口"], prefix='/space')
|
||||||
api_router.include_router(dashboard.router, tags=["看板接口"], prefix='/dashboard')
|
api_router.include_router(dashboard.router, tags=["看板接口"], prefix='/dashboard')
|
||||||
api_router.include_router(report.router, tags=["报表接口"], prefix='/report')
|
api_router.include_router(report.router, tags=["报表接口"], prefix='/report')
|
||||||
|
|
||||||
|
api_router.include_router(authority.router, tags=["权限管理接口"], prefix='/authority')
|
||||||
|
132
api/api_v1/endpoints/authority.py
Normal file
132
api/api_v1/endpoints/authority.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import pymongo
|
||||||
|
from fastapi import APIRouter, Depends, Request
|
||||||
|
from motor.motor_asyncio import AsyncIOMotorDatabase
|
||||||
|
import crud, schemas
|
||||||
|
from core.config import settings
|
||||||
|
from core.security import get_password_hash
|
||||||
|
|
||||||
|
from db import get_database
|
||||||
|
from api import deps
|
||||||
|
from utils import casbin_enforcer
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/api_list")
|
||||||
|
async def api_list(request: Request, current_user: schemas.UserDB = Depends(deps.get_current_user)) -> schemas.Msg:
|
||||||
|
"""api 列表"""
|
||||||
|
app = request.app
|
||||||
|
data = []
|
||||||
|
for r in app.routes:
|
||||||
|
path = r.path
|
||||||
|
name = r.description if hasattr(r, 'description') else r.name
|
||||||
|
data.append({'api': path, 'name': name})
|
||||||
|
return schemas.Msg(code=0, msg='ok', data=data)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/add_role")
|
||||||
|
async def add_role(request: Request, 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)
|
||||||
|
|
||||||
|
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,
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
|
||||||
|
return schemas.Msg(code=0, msg='ok')
|
||||||
|
|
||||||
|
|
||||||
|
@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")
|
||||||
|
async def set_role(request: Request,
|
||||||
|
data_id: schemas.AccountSetRole,
|
||||||
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
|
) -> schemas.Msg:
|
||||||
|
"""设置账号角色"""
|
||||||
|
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)
|
||||||
|
|
||||||
|
return schemas.Msg(code=0, msg='ok')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# @router.get("/delete_user")
|
||||||
|
# async def delete_user(request: Request,
|
||||||
|
# data_id: schemas.AccountDeleteUser,
|
||||||
|
# db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
|
# current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
|
# ) -> schemas.Msg:
|
||||||
|
# pass
|
||||||
|
# return schemas.Msg(code=0, msg='暂时没有')
|
@ -15,11 +15,11 @@ async def create(
|
|||||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
) -> schemas.Msg:
|
) -> schemas.Msg:
|
||||||
|
"""创建看板"""
|
||||||
try:
|
try:
|
||||||
await crud.dashboard.create(db, data_in, user_id=current_user.id)
|
await crud.dashboard.create(db, data_in, user_id=current_user.id)
|
||||||
except pymongo.errors.DuplicateKeyError:
|
except pymongo.errors.DuplicateKeyError:
|
||||||
return schemas.Msg(code=-1, msg='error', data='看板已存在')
|
return schemas.Msg(code=-1, msg='看板已存在', data='看板已存在')
|
||||||
# todo 建默认文件夹
|
|
||||||
|
|
||||||
return schemas.Msg(code=0, msg='ok', data='创建成功')
|
return schemas.Msg(code=0, msg='ok', data='创建成功')
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ async def delete(
|
|||||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
) -> schemas.Msg:
|
) -> schemas.Msg:
|
||||||
# 删除Dashboard 自己创建的
|
"""删除看板"""
|
||||||
del_dashboard = await crud.dashboard.delete(db, _id=data_in.id, user_id=current_user.id)
|
del_dashboard = await crud.dashboard.delete(db, _id=data_in.id, user_id=current_user.id)
|
||||||
|
|
||||||
if del_dashboard.deleted_count == 0:
|
if del_dashboard.deleted_count == 0:
|
||||||
@ -39,7 +39,7 @@ async def delete(
|
|||||||
|
|
||||||
|
|
||||||
@router.post("/move")
|
@router.post("/move")
|
||||||
async def delete(
|
async def move(
|
||||||
data_in: schemas.DashboardMove,
|
data_in: schemas.DashboardMove,
|
||||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
@ -58,12 +58,13 @@ async def add_report(data_in: schemas.AddReport,
|
|||||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
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')
|
return schemas.Msg(code=0, msg='ok', data='ok')
|
||||||
|
|
||||||
|
|
||||||
@router.post("/del_report")
|
@router.post("/del_report")
|
||||||
async def add_report(data_in: schemas.DelReport,
|
async def del_report(data_in: schemas.DelReport,
|
||||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
):
|
):
|
||||||
@ -74,7 +75,7 @@ async def add_report(data_in: schemas.DelReport,
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/")
|
@router.get("/")
|
||||||
async def add_report(_id: str,
|
async def dashboards(_id: str,
|
||||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
):
|
):
|
||||||
|
@ -19,7 +19,7 @@ async def create(
|
|||||||
try:
|
try:
|
||||||
await crud.folder.create(db, data_in, user_id=current_user.id)
|
await crud.folder.create(db, data_in, user_id=current_user.id)
|
||||||
except pymongo.errors.DuplicateKeyError:
|
except pymongo.errors.DuplicateKeyError:
|
||||||
return schemas.Msg(code=-1, msg='error', data='文件夹已存在')
|
return schemas.Msg(code=-1, msg='文件夹已存在', data='文件夹已存在')
|
||||||
# todo 建默认文件夹
|
# todo 建默认文件夹
|
||||||
|
|
||||||
return schemas.Msg(code=0, msg='ok', data='创建成功')
|
return schemas.Msg(code=0, msg='ok', data='创建成功')
|
||||||
|
@ -65,7 +65,8 @@ async def read_kanban(
|
|||||||
# 我的空间
|
# 我的空间
|
||||||
where = {
|
where = {
|
||||||
'project_id': data_in.id,
|
'project_id': data_in.id,
|
||||||
'$or': [{'rw_members': current_user.id}, {'r_members': current_user.id}]
|
'members._id': current_user.id
|
||||||
|
# '$or': [{'rw_members': current_user.id}, {'r_members': current_user.id}]
|
||||||
}
|
}
|
||||||
spaces = await crud.space.find_many(db, **where)
|
spaces = await crud.space.find_many(db, **where)
|
||||||
# 空间 文件夹 看板
|
# 空间 文件夹 看板
|
||||||
@ -75,7 +76,7 @@ async def read_kanban(
|
|||||||
'children': [],
|
'children': [],
|
||||||
'_id': item['_id']
|
'_id': item['_id']
|
||||||
})
|
})
|
||||||
res['spaces'][-1]['authority'] = 'rw' if current_user.id in item['rw_members'] else 'r'
|
res['spaces'][-1]['authority'] = 'rw' if current_user.id in item['members'] else 'r'
|
||||||
|
|
||||||
for f in await crud.folder.find_many(db, pid=item['_id']):
|
for f in await crud.folder.find_many(db, pid=item['_id']):
|
||||||
res['spaces'][-1]['children'].append({
|
res['spaces'][-1]['children'].append({
|
||||||
|
@ -17,10 +17,16 @@ async def create(
|
|||||||
) -> schemas.Msg:
|
) -> schemas.Msg:
|
||||||
"""创建空间"""
|
"""创建空间"""
|
||||||
try:
|
try:
|
||||||
await crud.space.create(db, data_in, user_id=current_user.id)
|
if data_in.is_all_member:
|
||||||
|
data_in.members.clear()
|
||||||
|
users = await crud.user.find_many(db)
|
||||||
|
for user in users:
|
||||||
|
if user['_id'] == current_user.id:
|
||||||
|
continue
|
||||||
|
data_in.members.append(schemas.space.Member(**user, authority=data_in.authority))
|
||||||
|
await crud.space.create(db, data_in, user=current_user)
|
||||||
except pymongo.errors.DuplicateKeyError:
|
except pymongo.errors.DuplicateKeyError:
|
||||||
return schemas.Msg(code=-1, msg='空间已存在', data='空间已存在')
|
return schemas.Msg(code=-1, msg='空间已存在', data='空间已存在')
|
||||||
# todo 建默认文件夹
|
|
||||||
|
|
||||||
return schemas.Msg(code=0, msg='创建成功', data='创建成功')
|
return schemas.Msg(code=0, msg='创建成功', data='创建成功')
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ class Settings(BaseSettings):
|
|||||||
FIRST_SUPERUSER_PASSWORD: str = '123456'
|
FIRST_SUPERUSER_PASSWORD: str = '123456'
|
||||||
FIRST_NAME: str = 'root'
|
FIRST_NAME: str = 'root'
|
||||||
|
|
||||||
|
DEFAULT_PASSWORD = '123456'
|
||||||
|
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8
|
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8
|
||||||
SECRET_KEY: str = 'ZaFX6EypK6PtuhGv11q4DLRvAb0csiLx4dbKUwLwCe8'
|
SECRET_KEY: str = 'ZaFX6EypK6PtuhGv11q4DLRvAb0csiLx4dbKUwLwCe8'
|
||||||
|
|
||||||
|
@ -4,3 +4,4 @@ from .crud_folder import folder
|
|||||||
from .crud_space import space
|
from .crud_space import space
|
||||||
from .crud_dashboard import dashboard
|
from .crud_dashboard import dashboard
|
||||||
from .crud_report import report
|
from .crud_report import report
|
||||||
|
from .crud_authority import authority
|
||||||
|
@ -25,3 +25,9 @@ class CRUDBase:
|
|||||||
|
|
||||||
async def update_one(self, db, id, **kwargs):
|
async def update_one(self, db, id, **kwargs):
|
||||||
return await db[self.coll_name].update_one({'_id': 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 distinct(self, db, key, filter=None):
|
||||||
|
return await db[self.coll_name].distinct(key, filter)
|
||||||
|
31
crud/crud_authority.py
Normal file
31
crud/crud_authority.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import pymongo
|
||||||
|
from motor.motor_asyncio import AsyncIOMotorDatabase
|
||||||
|
|
||||||
|
from core.config import settings
|
||||||
|
from crud.base import CRUDBase
|
||||||
|
from schemas import *
|
||||||
|
from utils import *
|
||||||
|
|
||||||
|
__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_index(self, db: AsyncIOMotorDatabase):
|
||||||
|
await db[self.coll_name].create_index(
|
||||||
|
[('ptype', pymongo.DESCENDING), ('v0', pymongo.DESCENDING), ('v1', pymongo.DESCENDING),
|
||||||
|
('v2', pymongo.DESCENDING)],
|
||||||
|
unique=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
authority = CRUDAuthority(settings.CASBIN_COLL)
|
@ -9,12 +9,11 @@ __all__ = 'space',
|
|||||||
|
|
||||||
class CRUDSpace(CRUDBase):
|
class CRUDSpace(CRUDBase):
|
||||||
|
|
||||||
async def create(self, db: AsyncIOMotorDatabase, obj_in: SpaceCreate, user_id: str):
|
async def create(self, db: AsyncIOMotorDatabase, obj_in: SpaceCreate, user: UserDB):
|
||||||
|
obj_in.members.append({'_id': user.id, 'name': user.name, 'authority': 'rw'})
|
||||||
db_obj = SpaceDB(
|
db_obj = SpaceDB(
|
||||||
**obj_in.dict(), user_id=user_id,
|
**obj_in.dict(by_alias=True), user_id=user.id,
|
||||||
rw_members=[user_id],
|
|
||||||
_id=uuid.uuid1().hex
|
_id=uuid.uuid1().hex
|
||||||
|
|
||||||
)
|
)
|
||||||
await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
|
await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class CRUDUser(CRUDBase):
|
|||||||
return user_obj
|
return user_obj
|
||||||
|
|
||||||
async def create_index(self, db: AsyncIOMotorDatabase):
|
async def create_index(self, db: AsyncIOMotorDatabase):
|
||||||
await db[self.coll_name].create_index('username', unique=True)
|
await db[self.coll_name].create_index('name', unique=True)
|
||||||
|
|
||||||
|
|
||||||
user = CRUDUser('user')
|
user = CRUDUser('user')
|
||||||
|
@ -38,10 +38,24 @@ async def space_index():
|
|||||||
async def dashboard_index():
|
async def dashboard_index():
|
||||||
await crud.dashboard.create_index(db)
|
await crud.dashboard.create_index(db)
|
||||||
|
|
||||||
|
|
||||||
async def report_index():
|
async def report_index():
|
||||||
await crud.report.create_index(db)
|
await crud.report.create_index(db)
|
||||||
|
|
||||||
|
|
||||||
|
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', '*')
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
await create_superuser()
|
await create_superuser()
|
||||||
await project_index()
|
await project_index()
|
||||||
@ -49,6 +63,7 @@ async def main():
|
|||||||
await space_index()
|
await space_index()
|
||||||
await dashboard_index()
|
await dashboard_index()
|
||||||
await report_index()
|
await report_index()
|
||||||
|
await authority_init()
|
||||||
|
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
13
db/init_menu.py
Normal file
13
db/init_menu.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
data = [
|
||||||
|
{'title': '用户接口', 'powerarr': [
|
||||||
|
{'title': '获取所有用户', 'path': '/api/v1/all_user'},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{'title': '项目接口', 'powerarr': [
|
||||||
|
{'title': '创建项目', 'path': '/api/v1/project/create'},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{'title': '文件夹接口', 'powerarr': [
|
||||||
|
{'title': '创建项目', 'path': '/api/v1/project/create'},
|
||||||
|
]},
|
||||||
|
]
|
45
main.py
45
main.py
@ -5,13 +5,15 @@ import uvicorn
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
import casbin
|
import casbin
|
||||||
|
|
||||||
|
from api.deps import get_current_user2
|
||||||
from core.config import settings
|
from core.config import settings
|
||||||
from starlette.middleware.cors import CORSMiddleware
|
from starlette.middleware.cors import CORSMiddleware
|
||||||
from starlette.authentication import AuthenticationBackend, AuthenticationError, SimpleUser, AuthCredentials
|
from starlette.authentication import AuthenticationBackend, AuthenticationError, AuthCredentials, BaseUser, SimpleUser
|
||||||
from starlette.middleware.authentication import AuthenticationMiddleware
|
from starlette.middleware.authentication import AuthenticationMiddleware
|
||||||
|
from fastapi_authz import CasbinMiddleware
|
||||||
|
|
||||||
|
from db import connect_to_mongo, close_mongo_connection, get_database
|
||||||
from db import connect_to_mongo, close_mongo_connection
|
from utils import *
|
||||||
|
|
||||||
app = FastAPI(title=settings.PROJECT_NAME)
|
app = FastAPI(title=settings.PROJECT_NAME)
|
||||||
|
|
||||||
@ -24,31 +26,50 @@ if settings.BACKEND_CORS_ORIGINS:
|
|||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
app.add_event_handler("startup", connect_to_mongo)
|
app.add_event_handler("startup", connect_to_mongo)
|
||||||
|
|
||||||
app.add_event_handler("shutdown", close_mongo_connection)
|
app.add_event_handler("shutdown", close_mongo_connection)
|
||||||
|
|
||||||
|
|
||||||
|
class CurrentUser(BaseUser):
|
||||||
|
def __init__(self, username: str, user_id: str) -> None:
|
||||||
|
self.username = username
|
||||||
|
self.id = user_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_authenticated(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def display_name(self) -> str:
|
||||||
|
return self.username
|
||||||
|
|
||||||
|
@property
|
||||||
|
def identity(self) -> str:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
class BasicAuth(AuthenticationBackend):
|
class BasicAuth(AuthenticationBackend):
|
||||||
async def authenticate(self, request):
|
async def authenticate(self, request):
|
||||||
if "Authorization" not in request.headers:
|
if "Authorization" not in request.headers:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
auth = request.headers["Authorization"]
|
auth = request.headers["Authorization"]
|
||||||
|
if len(auth) < 20:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
scheme, credentials = auth.split()
|
user = get_current_user2(auth.split(' ')[1])
|
||||||
decoded = base64.b64decode(credentials).decode("ascii")
|
|
||||||
except (ValueError, UnicodeDecodeError, binascii.Error):
|
except (ValueError, UnicodeDecodeError, binascii.Error):
|
||||||
raise AuthenticationError("Invalid basic auth credentials")
|
raise AuthenticationError("Invalid basic auth credentials")
|
||||||
|
|
||||||
username, _, password = decoded.partition(":")
|
return AuthCredentials(["authenticated"]), CurrentUser(user.name, user.id)
|
||||||
return AuthCredentials(["authenticated"]), SimpleUser(username)
|
|
||||||
|
|
||||||
# enforcer = casbin.Enforcer('rbac_model.conf', 'rbac_policy.csv')
|
|
||||||
# app.add_middleware(CasbinMiddleware, enforcer=enforcer)
|
app.add_middleware(CasbinMiddleware, enforcer=casbin_enforcer)
|
||||||
# app.add_middleware(AuthenticationMiddleware, backend=BasicAuth())
|
app.add_middleware(AuthenticationMiddleware, backend=BasicAuth())
|
||||||
|
|
||||||
from api.api_v1.api import api_router
|
from api.api_v1.api import api_router
|
||||||
|
|
||||||
app.include_router(api_router, prefix=settings.API_V1_STR)
|
app.include_router(api_router, prefix=settings.API_V1_STR)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
uvicorn.run(app='main:app', host="0.0.0.0", port=8889, reload=True, debug=True)
|
uvicorn.run(app='main2:app', host="0.0.0.0", port=8889, reload=True, debug=True)
|
||||||
|
11
main2.py
11
main2.py
@ -13,7 +13,7 @@ from starlette.middleware.authentication import AuthenticationMiddleware
|
|||||||
from fastapi_authz import CasbinMiddleware
|
from fastapi_authz import CasbinMiddleware
|
||||||
|
|
||||||
from db import connect_to_mongo, close_mongo_connection, get_database
|
from db import connect_to_mongo, close_mongo_connection, get_database
|
||||||
from utils import Adapter
|
from utils import *
|
||||||
|
|
||||||
app = FastAPI(title=settings.PROJECT_NAME)
|
app = FastAPI(title=settings.PROJECT_NAME)
|
||||||
|
|
||||||
@ -64,17 +64,12 @@ class BasicAuth(AuthenticationBackend):
|
|||||||
return AuthCredentials(["authenticated"]), CurrentUser(user.name, user.id)
|
return AuthCredentials(["authenticated"]), CurrentUser(user.name, user.id)
|
||||||
|
|
||||||
|
|
||||||
|
app.add_middleware(CasbinMiddleware, enforcer=casbin_enforcer)
|
||||||
enforcer = casbin.Enforcer('rbac_model.conf', Adapter(settings.DATABASE_URI,settings.MDB_DB))
|
|
||||||
app.add_middleware(CasbinMiddleware, enforcer=enforcer)
|
|
||||||
app.add_middleware(AuthenticationMiddleware, backend=BasicAuth())
|
app.add_middleware(AuthenticationMiddleware, backend=BasicAuth())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from api.api_v1.api import api_router
|
from api.api_v1.api import api_router
|
||||||
|
|
||||||
app.include_router(api_router, prefix=settings.API_V1_STR)
|
app.include_router(api_router, prefix=settings.API_V1_STR)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
uvicorn.run(app='main2:app', host="0.0.0.0", port=8899, reload=True, debug=True)
|
uvicorn.run(app='main2:app', host="0.0.0.0", port=8899, reload=True, debug=True)
|
||||||
|
@ -3,19 +3,19 @@ import casbin
|
|||||||
from core.config import settings
|
from core.config import settings
|
||||||
from pymongo import MongoClient
|
from pymongo import MongoClient
|
||||||
|
|
||||||
from utils import Adapter
|
from utils import *
|
||||||
|
|
||||||
client = MongoClient(settings.DATABASE_URI)
|
client = MongoClient(settings.DATABASE_URI)
|
||||||
db = client[settings.MDB_DB]
|
db = client[settings.MDB_DB]
|
||||||
collection = db[settings.CASBIN_COLL]
|
collection = db[settings.CASBIN_COLL]
|
||||||
|
|
||||||
adapter = Adapter(settings.DATABASE_URI, settings.MDB_DB)
|
|
||||||
enforcer = casbin.Enforcer('rbac_model.conf', adapter)
|
|
||||||
|
|
||||||
model = enforcer.get_model()
|
|
||||||
model.add_policy('g', 'g', ['root', 'superAdmin', ])
|
|
||||||
model.add_policy('g', 'g', ['legu', 'admin'])
|
|
||||||
adapter.save_policy(model)
|
|
||||||
|
|
||||||
res = enforcer.enforce('alice', 'data1', 'read')
|
|
||||||
|
# casbin_model.add_policy('g', 'g', ['root', 'superAdmin', ])
|
||||||
|
# casbin_model.add_policy('g', 'g', ['legu', 'admin'])
|
||||||
|
# casbin_enforcer.add_role_for_user('user', 'role')
|
||||||
|
res = casbin_enforcer.delete_user('user')
|
||||||
print(res)
|
print(res)
|
||||||
|
casbin_adapter.save_policy(casbin_model)
|
||||||
|
|
||||||
|
@ -4,4 +4,5 @@ from .project import *
|
|||||||
from .folder import *
|
from .folder import *
|
||||||
from .space import *
|
from .space import *
|
||||||
from .dashboard import *
|
from .dashboard import *
|
||||||
from .report import *
|
from .report import *
|
||||||
|
from .authotity import *
|
35
schemas/authotity.py
Normal file
35
schemas/authotity.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
from enum import Enum
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Ptype(str, Enum):
|
||||||
|
p = 'p'
|
||||||
|
g = 'g'
|
||||||
|
|
||||||
|
|
||||||
|
class CasbinRoleCreate(BaseModel):
|
||||||
|
role_name: str
|
||||||
|
role_api: List
|
||||||
|
|
||||||
|
|
||||||
|
class CasbinDB(BaseModel):
|
||||||
|
ptype: Ptype
|
||||||
|
v0: str
|
||||||
|
v1: str
|
||||||
|
v2: str
|
||||||
|
|
||||||
|
|
||||||
|
class AccountCreate(BaseModel):
|
||||||
|
name: str
|
||||||
|
role_name: str
|
||||||
|
|
||||||
|
|
||||||
|
class AccountDeleteUser(BaseModel):
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
class AccountSetRole(BaseModel):
|
||||||
|
name: str
|
||||||
|
role_name: str
|
@ -12,10 +12,23 @@ class SpaceBase(BaseModel):
|
|||||||
name: str = None
|
name: str = None
|
||||||
|
|
||||||
|
|
||||||
|
class Authority(str, Enum):
|
||||||
|
rw = 'rw'
|
||||||
|
r = 'r'
|
||||||
|
|
||||||
|
|
||||||
|
class Member(DBBase):
|
||||||
|
name: str
|
||||||
|
authority: Authority
|
||||||
|
|
||||||
|
|
||||||
# 解析请求json 创建项目
|
# 解析请求json 创建项目
|
||||||
class SpaceCreate(SpaceBase):
|
class SpaceCreate(SpaceBase):
|
||||||
name: str
|
name: str
|
||||||
project_id: str
|
project_id: str
|
||||||
|
members: List[Member] = []
|
||||||
|
is_all_member: bool = False
|
||||||
|
authority: Authority = 'r'
|
||||||
|
|
||||||
|
|
||||||
class SpaceDelete(DBBase):
|
class SpaceDelete(DBBase):
|
||||||
@ -28,6 +41,5 @@ class SpaceDB(DBBase):
|
|||||||
name: str
|
name: str
|
||||||
user_id: str
|
user_id: str
|
||||||
project_id: str
|
project_id: str
|
||||||
rw_members: List[str] = []
|
members: List[Member] = []
|
||||||
r_members: List[str] = []
|
|
||||||
create_date: datetime = datetime.now()
|
create_date: datetime = datetime.now()
|
||||||
|
@ -21,8 +21,8 @@ class UserLogin(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class UserCreate(UserBase):
|
class UserCreate(UserBase):
|
||||||
email: EmailStr
|
|
||||||
password: str
|
password: str
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
# ****************************************************************************
|
# ****************************************************************************
|
||||||
@ -30,13 +30,10 @@ class UserCreate(UserBase):
|
|||||||
|
|
||||||
|
|
||||||
class UserDB(DBBase):
|
class UserDB(DBBase):
|
||||||
email: EmailStr
|
email: EmailStr = None
|
||||||
is_superuser: bool
|
is_superuser: bool = False
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
|
|
||||||
class UserDBRW(UserDB):
|
class UserDBRW(UserDB):
|
||||||
hashed_password: str
|
hashed_password: str
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
from .adapter import Adapter
|
from .adapter import *
|
||||||
|
@ -2,6 +2,10 @@ import casbin
|
|||||||
from casbin import persist
|
from casbin import persist
|
||||||
from pymongo import MongoClient
|
from pymongo import MongoClient
|
||||||
|
|
||||||
|
from core.config import settings
|
||||||
|
|
||||||
|
__all__ = 'casbin_adapter', 'casbin_enforcer', 'casbin_model'
|
||||||
|
|
||||||
|
|
||||||
class CasbinRule:
|
class CasbinRule:
|
||||||
'''
|
'''
|
||||||
@ -82,7 +86,7 @@ class Adapter(persist.Adapter):
|
|||||||
line.v4 = rule[4]
|
line.v4 = rule[4]
|
||||||
if len(rule) > 5:
|
if len(rule) > 5:
|
||||||
line.v5 = rule[5]
|
line.v5 = rule[5]
|
||||||
self._collection.update_one(line.dict(), {'$set':line.dict()}, upsert=True)
|
self._collection.update_one(line.dict(), {'$set': line.dict()}, upsert=True)
|
||||||
|
|
||||||
def save_policy(self, model):
|
def save_policy(self, model):
|
||||||
'''
|
'''
|
||||||
@ -110,3 +114,8 @@ class Adapter(persist.Adapter):
|
|||||||
delete policy rules for matching filters from mongodb
|
delete policy rules for matching filters from mongodb
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
casbin_adapter = Adapter(settings.DATABASE_URI, settings.MDB_DB)
|
||||||
|
casbin_enforcer = casbin.Enforcer('rbac_model.conf', casbin_adapter)
|
||||||
|
casbin_model = casbin_enforcer.get_model()
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
from casbin import persist
|
from casbin import persist
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user