مدیریت سطح دسترسی کاربران در GraphQL با FastAPI و JWT
در پروژههای GraphQL، همه درخواستها معمولاً از یک endpoint واحد (/graphql
) عبور میکنند، بنابراین مدیریت سطح دسترسی باید در Resolverها یا با استفاده از Middleware انجام شود. این کار تضمین میکند که کاربران تنها به بخشهایی از دادهها که مجاز هستند، دسترسی داشته باشند.
۱. تعریف نقشها (Roles)
# models/users.py
from sqlalchemy import Column, Integer, String
from config.database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, nullable=False)
password = Column(String, nullable=False)
role = Column(String, default="user") # user یا admin
۲. Dependency برای بررسی نقش کاربر
# graphql/context.py
from fastapi import Header
from utils.jwt import decode_access_token
from config.database import SessionLocal
from models.users import User
def get_current_user(authorization: str = Header(None)):
if not authorization:
raise Exception("Missing Authorization header")
token = authorization.replace("Bearer ", "")
payload = decode_access_token(token)
db = SessionLocal()
user = db.query(User).filter(User.id == payload.get("user_id")).first()
db.close()
if not user:
raise Exception("User not found")
return user
def require_role(user, allowed_roles: list[str]):
if user.role not in allowed_roles:
raise Exception("Unauthorized: insufficient permissions")
return True
۳. اعمال سطح دسترسی در Resolver
# graphql/tasks.py
import strawberry
from graphql.context import get_current_user, require_role
from models.tasks import Task as TaskModel
from graphql.types import TaskType
@strawberry.type
class TaskMutation:
@strawberry.mutation
def create_task(self, info, title: str, user_id: int) -> TaskType:
db = info.context["db"]
auth_header = info.context["request"].headers.get("authorization")
current_user = get_current_user(auth_header, db)
require_role(current_user, ["admin", "user"])
if current_user.role != "admin" and current_user.id != user_id:
raise Exception("Unauthorized: cannot create task for other users")
task = TaskModel(title=title, user_id=user_id)
db.add(task)
db.commit()
db.refresh(task)
return TaskType(
id=task.id,
title=task.title,
completed=task.completed,
user_id=task.user_id,
created_at=str(task.created_at),
updated_at=str(task.updated_at)
)
توضیح
- هر کاربر دارای نقش
role
است، مثلاًuser
یاadmin
. - تابع
require_role
بررسی میکند که کاربر دسترسی لازم برای اجرای عملیات را دارد یا خیر. - در Resolverها میتوان محدودیتهای دقیقتری هم اعمال کرد، مثلاً اجازه ایجاد یا ویرایش فقط برای مالک داده یا مدیر سیستم.
- میتوان این مکانیزم را در یک Middleware یا Extension GraphQL نیز پیاده کرد تا تمام Resolverها یکدست مدیریت شوند.
با این روش، میتوانیم کنترل دقیقی روی سطح دسترسی کاربران در تمام Query و Mutationهای GraphQL داشته باشیم و امنیت پروژه را افزایش دهیم.