跳转至

权限控制

权限控制是保护 API 的关键。fastapi-easy 支持基于角色的访问控制(RBAC)和基于属性的访问控制(ABAC)。


什么是权限控制?

权限控制可以:

  • ✅ 限制用户访问
  • ✅ 保护敏感数据
  • ✅ 实现多租户
  • ✅ 审计用户操作

基于角色的访问控制(RBAC)

定义角色和权限

from fastapi_easy.core.permissions import Role, Permission, RoleBasedAccessControl

# 定义权限
class Permission(str, Enum):
    CREATE = "create"
    READ = "read"
    UPDATE = "update"
    DELETE = "delete"
    ADMIN = "admin"

# 定义角色
class Role(str, Enum):
    ADMIN = "admin"
    EDITOR = "editor"
    VIEWER = "viewer"
    USER = "user"

# 创建 RBAC 实例
rbac = RoleBasedAccessControl()

# 配置角色权限
rbac.add_permission(Role.ADMIN, Permission.ADMIN)
rbac.add_permission(Role.EDITOR, Permission.CREATE)
rbac.add_permission(Role.EDITOR, Permission.READ)
rbac.add_permission(Role.EDITOR, Permission.UPDATE)
rbac.add_permission(Role.VIEWER, Permission.READ)
rbac.add_permission(Role.USER, Permission.READ)

检查权限

# 检查用户是否有权限
if rbac.has_permission(Role.EDITOR, Permission.UPDATE):
    # 允许更新
    pass
else:
    # 拒绝更新
    raise PermissionDeniedError("No permission to update")

基于属性的访问控制(ABAC)

定义策略

from fastapi_easy.core.permissions import AttributeBasedAccessControl

abac = AttributeBasedAccessControl()

# 添加策略:只有所有者可以删除自己的项目
abac.add_policy(
    name="owner_delete",
    resource="item",
    action="delete",
    condition=lambda context: context.user_id == context.resource.owner_id
)

# 添加策略:只有管理员可以删除任何项目
abac.add_policy(
    name="admin_delete",
    resource="item",
    action="delete",
    condition=lambda context: "admin" in context.user_roles
)

评估策略

from fastapi_easy.core.permissions import PermissionContext

# 创建权限上下文
context = PermissionContext(
    user_id=user.id,
    roles=user.roles,
    permissions=user.permissions,
    attributes={"resource": item}
)

# 检查是否允许删除
if abac.evaluate(context, "item", "delete"):
    # 允许删除
    pass
else:
    # 拒绝删除
    raise PermissionDeniedError("No permission to delete this item")

集成到 CRUDRouter

配置权限

from fastapi_easy import CRUDRouter
from fastapi_easy.core.permissions import PermissionConfig

config = PermissionConfig(
    enabled=True,
    default_role=Role.USER,
    require_authentication=True,
)

router = CRUDRouter(
    schema=ItemSchema,
    backend=backend,
    permission_config=config,
    rbac=rbac,
    abac=abac,
)

在钩子中检查权限

async def before_create(context):
    # 检查创建权限
    if not rbac.has_permission(context.user_role, Permission.CREATE):
        raise PermissionDeniedError("No permission to create")

async def before_delete(context):
    # 检查删除权限
    if not abac.evaluate(context, "item", "delete"):
        raise PermissionDeniedError("No permission to delete this item")

router.hooks.register("before_create", before_create)
router.hooks.register("before_delete", before_delete)

高级用法

多租户支持

# 添加策略:用户只能访问自己租户的数据
abac.add_policy(
    name="tenant_isolation",
    resource="item",
    action="read",
    condition=lambda context: context.tenant_id == context.resource.tenant_id
)

动态权限

# 根据时间限制访问
abac.add_policy(
    name="time_based_access",
    resource="item",
    action="update",
    condition=lambda context: context.is_business_hours()
)

# 根据数据敏感性限制访问
abac.add_policy(
    name="data_sensitivity",
    resource="item",
    action="read",
    condition=lambda context: context.user_clearance_level >= context.resource.sensitivity_level
)

最佳实践

1. 使用最小权限原则

# ✅ 推荐:最小权限
rbac.add_permission(Role.USER, Permission.READ)

# ❌ 不推荐:过度权限
rbac.add_permission(Role.USER, Permission.ADMIN)

2. 定期审计权限

# 定期检查用户权限
for user in users:
    permissions = rbac.get_permissions(user.role)
    logger.info(f"User {user.id} permissions: {permissions}")

3. 使用权限缓存

# 缓存权限检查结果
from functools import lru_cache

@lru_cache(maxsize=1000)
def check_permission(role: str, permission: str) -> bool:
    return rbac.has_permission(role, permission)

4. 记录权限拒绝

# 记录所有权限拒绝
try:
    if not rbac.has_permission(user_role, permission):
        raise PermissionDeniedError()
except PermissionDeniedError:
    logger.warning(f"Permission denied: {user_id} -> {permission}")
    raise

常见问题

Q: RBAC 和 ABAC 有什么区别?

A: RBAC 基于用户角色,ABAC 基于属性和条件。ABAC 更灵活。

Q: 如何实现多租户?

A: 使用 ABAC 添加租户隔离策略。

Q: 如何处理权限拒绝?

A: 抛出 PermissionDeniedError 异常,由中间件处理。

Q: 权限检查会影响性能吗?

A: 会有轻微影响,建议使用缓存。


总结

权限控制是保护 API 的关键:

  • ✅ 使用 RBAC 进行基本权限管理
  • ✅ 使用 ABAC 进行复杂权限管理
  • ✅ 遵循最小权限原则
  • ✅ 定期审计权限

下一步: 审计日志