파이썬/Fast API

FastAPI Permissions: 권한 관리 구현

코샵 2025. 2. 22. 10:37
반응형
# 설치
pip install fastapi-permissions

기본 권한 설정

from fastapi_permissions import (
    Allow,
    Deny,
    Everyone,
    Authenticated,
    configure_permissions,
    has_permission
)

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)
    email = Column(String, unique=True)
    role = Column(String)

    def __acl__(self):
        return [
            (Allow, "admin", "read"),
            (Allow, "admin", "write"),
            (Allow, "editor", "read"),
            (Deny, Everyone, "write")
        ]

권한 확인 미들웨어 설정

from fastapi import FastAPI, Depends, HTTPException
from fastapi_permissions import configure_permissions

app = FastAPI()

# 현재 사용자 가져오기
async def get_current_user():
    # 사용자 인증 로직
    return current_user

# 권한 설정
get_permission = configure_permissions(get_current_user)

@app.get("/items/{item_id}")
async def read_item(
    item_id: int,
    permission = Depends(get_permission("read"))
):
    if not has_permission(permission, "read"):
        raise HTTPException(status_code=403, detail="Permission denied")
    return {"item_id": item_id}

리소스별 권한 구현

class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True)
    name = Column(String)
    owner_id = Column(Integer, ForeignKey("users.id"))

    def __acl__(self):
        return [
            (Allow, f"user:{self.owner_id}", "read"),
            (Allow, f"user:{self.owner_id}", "write"),
            (Allow, "admin", "read"),
            (Allow, "admin", "write"),
            (Allow, "editor", "read"),
            (Deny, Everyone, "write")
        ]

@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Item,
    permission = Depends(get_permission("write"))
):
    if not has_permission(permission, "write", item):
        raise HTTPException(status_code=403, detail="Permission denied")
    return {"status": "updated"}

역할 기반 권한 관리

class Role(Base):
    __tablename__ = "roles"

    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True)
    permissions = Column(ARRAY(String))

class UserRole(Base):
    __tablename__ = "user_roles"

    user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
    role_id = Column(Integer, ForeignKey("roles.id"), primary_key=True)

async def check_role_permission(
    user: User,
    required_roles: list[str]
):
    user_roles = await get_user_roles(user.id)
    return any(role.name in required_roles for role in user_roles)

커스텀 권한 데코레이터

from functools import wraps

def require_permissions(*permissions):
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            permission = kwargs.get('permission')
            if not permission:
                raise HTTPException(
                    status_code=403,
                    detail="Permission check failed"
                )

            for perm in permissions:
                if not has_permission(permission, perm):
                    raise HTTPException(
                        status_code=403,
                        detail=f"Missing permission: {perm}"
                    )

            return await func(*args, **kwargs)
        return wrapper
    return decorator

@app.get("/admin/users")
@require_permissions("read:users", "manage:users")
async def list_users(permission = Depends(get_permission())):
    return {"users": []}

권한 그룹 관리

class PermissionGroup:
    def __init__(self, name: str, permissions: list[str]):
        self.name = name
        self.permissions = permissions

    def __acl__(self):
        return [
            (Allow, f"group:{self.name}", perm)
            for perm in self.permissions
        ]

# 권한 그룹 정의
ADMIN_GROUP = PermissionGroup("admin", [
    "read:all",
    "write:all",
    "delete:all"
])

EDITOR_GROUP = PermissionGroup("editor", [
    "read:all",
    "write:content"
])

@app.delete("/items/{item_id}")
async def delete_item(
    item_id: int,
    permission = Depends(get_permission("delete:all"))
):
    if not has_permission(permission, "delete:all"):
        raise HTTPException(status_code=403, detail="Permission denied")
    return {"status": "deleted"}

권한 캐싱

from functools import lru_cache
from typing import List

@lru_cache(maxsize=1000)
async def get_user_permissions(user_id: int) -> List[str]:
    user_roles = await get_user_roles(user_id)
    permissions = set()

    for role in user_roles:
        permissions.update(role.permissions)

    return list(permissions)

async def verify_permission(
    user_id: int,
    required_permission: str
):
    user_permissions = await get_user_permissions(user_id)
    return required_permission in user_permissions

 

주요 기능 및 장점

  1. 세밀한 권한 제어
    • 리소스별 권한 설정
    • 역할 기반 접근 제어
    • 동적 권한 확인
  2. 유연한 확장성
    • 커스텀 권한 로직 구현
    • 권한 그룹 관리
    • 캐싱 지원
  3. 보안성
    • 선언적 권한 정의
    • 중앙화된 권한 관리
    • 상세한 접근 제어
  4. 사용 편의성
    • 직관적인 API
    • 데코레이터 기반 구현
    • 미들웨어 통합

FastAPI Permissions를 사용하면 복잡한 권한 관리 시스템을 효율적으로 구현할 수 있습니다.