2026-04-20 17:11:31 +08:00
|
|
|
from typing import Optional
|
|
|
|
|
from uuid import UUID
|
|
|
|
|
|
|
|
|
|
from fastapi import HTTPException
|
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
|
from sqlmodel import select
|
|
|
|
|
|
|
|
|
|
from ..model import Permission, RolePermission, Role, User
|
|
|
|
|
from .user import UserService
|
|
|
|
|
from .role import RoleService
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PermissionService:
|
2026-04-26 21:57:17 +08:00
|
|
|
"""权限服务类,提供权限的创建、查询、分配和解除绑定等功能"""
|
|
|
|
|
|
2026-04-20 17:11:31 +08:00
|
|
|
@classmethod
|
|
|
|
|
async def create_permission(
|
|
|
|
|
cls,
|
|
|
|
|
session: AsyncSession,
|
|
|
|
|
name: str,
|
|
|
|
|
resource: str,
|
|
|
|
|
action: str,
|
|
|
|
|
description: Optional[str] = None,
|
|
|
|
|
) -> Permission:
|
2026-04-26 21:57:17 +08:00
|
|
|
"""
|
|
|
|
|
创建新的权限记录
|
|
|
|
|
|
|
|
|
|
:param session: 数据库会话对象
|
|
|
|
|
:param name: 权限名称
|
|
|
|
|
:param resource: 资源标识
|
|
|
|
|
:param action: 操作类型
|
|
|
|
|
:param description: 权限描述,可选
|
|
|
|
|
:return: 创建的权限对象
|
|
|
|
|
"""
|
2026-04-20 17:11:31 +08:00
|
|
|
permission = Permission(
|
|
|
|
|
name=name, resource=resource, action=action, description=description
|
|
|
|
|
)
|
|
|
|
|
session.add(permission)
|
|
|
|
|
await session.commit()
|
|
|
|
|
await session.refresh(permission)
|
|
|
|
|
return permission
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
async def get_permission_by_id(
|
|
|
|
|
cls, session: AsyncSession, permission_id: int
|
|
|
|
|
) -> Optional[Permission]:
|
2026-04-26 21:57:17 +08:00
|
|
|
"""
|
|
|
|
|
根据ID获取权限
|
|
|
|
|
|
|
|
|
|
:param session: 数据库会话对象
|
|
|
|
|
:param permission_id: 权限ID
|
|
|
|
|
:return: 权限对象,如果不存在则返回None
|
|
|
|
|
"""
|
2026-04-20 17:11:31 +08:00
|
|
|
return await session.get(Permission, permission_id)
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
async def get_permission_by_name(
|
|
|
|
|
cls, session: AsyncSession, name: str
|
|
|
|
|
) -> Optional[Permission]:
|
2026-04-26 21:57:17 +08:00
|
|
|
"""
|
|
|
|
|
根据名称获取权限
|
|
|
|
|
|
|
|
|
|
:param session: 数据库会话对象
|
|
|
|
|
:param name: 权限名称
|
|
|
|
|
:return: 权限对象,如果不存在则返回None
|
|
|
|
|
"""
|
2026-04-20 17:11:31 +08:00
|
|
|
result = await session.execute(
|
|
|
|
|
select(Permission).where(Permission.name == name)
|
|
|
|
|
)
|
|
|
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
async def assign_permission_to_role(
|
|
|
|
|
cls, session: AsyncSession, role_id: int, permission_id: int
|
|
|
|
|
) -> RolePermission:
|
2026-04-26 21:57:17 +08:00
|
|
|
"""
|
|
|
|
|
将权限分配给角色
|
|
|
|
|
|
|
|
|
|
:param session: 数据库会话对象
|
|
|
|
|
:param role_id: 角色ID
|
|
|
|
|
:param permission_id: 权限ID
|
|
|
|
|
:return: 创建的角色权限关联对象
|
|
|
|
|
"""
|
2026-04-20 17:11:31 +08:00
|
|
|
role_permission = RolePermission(role_id=role_id, permission_id=permission_id)
|
|
|
|
|
session.add(role_permission)
|
|
|
|
|
await session.commit()
|
|
|
|
|
await session.refresh(role_permission)
|
|
|
|
|
return role_permission
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
async def assign_permission_to_user(
|
|
|
|
|
cls,
|
|
|
|
|
session: AsyncSession,
|
|
|
|
|
user_id: UUID,
|
|
|
|
|
permission_id: int,
|
|
|
|
|
) -> User:
|
2026-04-26 21:57:17 +08:00
|
|
|
"""
|
|
|
|
|
将权限分配给用户
|
|
|
|
|
|
|
|
|
|
如果用户没有专属角色,则会为用户创建一个专属角色,然后将权限分配给该角色
|
|
|
|
|
|
|
|
|
|
:param session: 数据库会话对象
|
|
|
|
|
:param user_id: 用户UUID
|
|
|
|
|
:param permission_id: 权限ID
|
|
|
|
|
:return: 更新后的用户对象
|
|
|
|
|
:raises HTTPException: 当权限或用户不存在时抛出404错误,当角色或权限ID无效时抛出500错误
|
|
|
|
|
"""
|
|
|
|
|
# 验证权限是否存在
|
2026-04-20 17:11:31 +08:00
|
|
|
permission = await cls.get_permission_by_id(session, permission_id)
|
|
|
|
|
if not permission:
|
|
|
|
|
raise HTTPException(status_code=404, detail="Permission not found")
|
2026-04-26 21:57:17 +08:00
|
|
|
|
|
|
|
|
# 验证用户是否存在
|
2026-04-20 17:11:31 +08:00
|
|
|
user = await UserService.get_user_by_id(user_id, session)
|
|
|
|
|
if user is None:
|
|
|
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
2026-04-26 21:57:17 +08:00
|
|
|
|
|
|
|
|
# 获取或创建用户的专属角色
|
2026-04-20 17:11:31 +08:00
|
|
|
role = await RoleService.get_role_by_name(session, str(user_id))
|
|
|
|
|
if role is None:
|
|
|
|
|
role = await RoleService.create_role(
|
|
|
|
|
session, str(user_id), is_only_user=True
|
|
|
|
|
)
|
2026-04-26 21:57:17 +08:00
|
|
|
|
|
|
|
|
# 验证角色和权限ID的有效性
|
2026-04-20 17:11:31 +08:00
|
|
|
if role.id is None:
|
|
|
|
|
raise HTTPException(status_code=500, detail="角色ID无效")
|
|
|
|
|
if permission.id is None:
|
|
|
|
|
raise HTTPException(status_code=500, detail="权限ID无效")
|
2026-04-26 21:57:17 +08:00
|
|
|
|
|
|
|
|
# 将权限分配给角色
|
2026-04-20 17:11:31 +08:00
|
|
|
await cls.assign_permission_to_role(session, role.id, permission.id)
|
|
|
|
|
user.roles.append(role)
|
|
|
|
|
await session.commit()
|
|
|
|
|
await session.refresh(user)
|
|
|
|
|
return user
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
async def unbind_permission_from_role(
|
|
|
|
|
cls, session: AsyncSession, role_id: int, permission_id: int
|
|
|
|
|
) -> Role:
|
2026-04-26 21:57:17 +08:00
|
|
|
"""
|
|
|
|
|
从角色中解除权限绑定
|
|
|
|
|
|
|
|
|
|
:param session: 数据库会话对象
|
|
|
|
|
:param role_id: 角色ID
|
|
|
|
|
:param permission_id: 权限ID
|
|
|
|
|
:return: 更新后的角色对象
|
|
|
|
|
:raises HTTPException: 当角色不存在时抛出404错误
|
|
|
|
|
"""
|
|
|
|
|
# 验证角色是否存在
|
2026-04-20 17:11:31 +08:00
|
|
|
role = await RoleService.get_role_by_id(session, role_id)
|
|
|
|
|
if role is None:
|
|
|
|
|
raise HTTPException(status_code=404, detail="Role not found")
|
2026-04-26 21:57:17 +08:00
|
|
|
|
|
|
|
|
# 从角色的权限列表中移除指定权限
|
2026-04-20 17:11:31 +08:00
|
|
|
role.permissions = [p for p in role.permissions if p.id != permission_id]
|
|
|
|
|
await session.commit()
|
|
|
|
|
await session.refresh(role)
|
|
|
|
|
return role
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
async def unbind_permission_from_user(
|
|
|
|
|
cls, session: AsyncSession, user_id: UUID, permission_id: int
|
|
|
|
|
):
|
2026-04-26 21:57:17 +08:00
|
|
|
"""
|
|
|
|
|
从用户中解除权限绑定
|
|
|
|
|
|
|
|
|
|
通过找到用户的专属角色,从该角色中移除指定权限
|
|
|
|
|
|
|
|
|
|
:param session: 数据库会话对象
|
|
|
|
|
:param user_id: 用户UUID
|
|
|
|
|
:param permission_id: 权限ID
|
|
|
|
|
:raises HTTPException: 当用户或角色不存在时抛出404错误
|
|
|
|
|
"""
|
|
|
|
|
# 验证用户是否存在
|
2026-04-20 17:11:31 +08:00
|
|
|
user = await UserService.get_user_by_id(user_id, session)
|
|
|
|
|
if not user:
|
|
|
|
|
raise HTTPException(status_code=404, detail="User not found")
|
2026-04-26 21:57:17 +08:00
|
|
|
|
|
|
|
|
# 获取用户的专属角色
|
2026-04-20 17:11:31 +08:00
|
|
|
role = await RoleService.get_role_by_name(session, str(user.id))
|
|
|
|
|
if role is None:
|
|
|
|
|
raise HTTPException(status_code=404, detail="Role not found")
|
2026-04-26 21:57:17 +08:00
|
|
|
|
|
|
|
|
# 从角色权限列表中移除指定权限
|
2026-04-20 17:11:31 +08:00
|
|
|
role.permissions = [
|
|
|
|
|
permission
|
|
|
|
|
for permission in role.permissions
|
|
|
|
|
if permission.id != permission_id
|
|
|
|
|
]
|
|
|
|
|
await session.commit()
|
|
|
|
|
await session.refresh(role)
|