APIهای Django REST Framework خود را با احراز هویت قوی ایمن کنید. احراز هویت توکن و پیادهسازی JWT (JSON Web Token) را مقایسه کنید، از جمله مثالهای کد عملی و بهترین شیوهها.
احراز هویت Python DRF: پیادهسازی توکن در مقابل JWT برای APIهای قوی
ایمنسازی APIهای شما بسیار مهم است. هنگام ساخت API با پایتون و Django REST Framework (DRF)، چندین گزینه احراز هویت در دسترس دارید. این مقاله به بررسی دو روش محبوب میپردازد: احراز هویت توکن و احراز هویت JWT (JSON Web Token)، مقایسه نقاط قوت و ضعف آنها و ارائه مثالهای پیادهسازی عملی.
درک احراز هویت در APIها
احراز هویت فرآیند تأیید هویت یک کاربر یا برنامه است که به API شما دسترسی دارد. یک سیستم احراز هویت به خوبی پیادهسازیشده تضمین میکند که فقط نهادهای مجاز میتوانند به منابع محافظتشده دسترسی داشته باشند. در چارچوب APIهای RESTful، احراز هویت معمولاً شامل ارسال اعتبارنامهها (به عنوان مثال، نام کاربری و رمز عبور) با هر درخواست است. سپس سرور این اعتبارنامهها را تأیید میکند و در صورت معتبر بودن، دسترسی را اعطا میکند.
احراز هویت توکن
احراز هویت توکن یک مکانیسم ساده و سرراست است. هنگامی که یک کاربر با موفقیت وارد سیستم میشود، سرور یک توکن تصادفی و منحصربهفرد ایجاد میکند و آن را در پایگاه داده ذخیره میکند و آن را با کاربر مرتبط میکند. سپس مشتری این توکن را در هدر 'Authorization' درخواستهای بعدی ارسال میکند. سرور توکن را از پایگاه داده بازیابی میکند، اعتبار آن را تأیید میکند و بر این اساس دسترسی را اعطا میکند.
پیادهسازی با DRF
DRF پشتیبانی داخلی از احراز هویت توکن را فراهم میکند. در اینجا نحوه پیادهسازی آن آمده است:
- DRF را نصب کنید و آن را در پروژه Django خود ثبت کنید:
ابتدا مطمئن شوید که Django REST Framework را نصب کردهاید:
pip install djangorestframework
سپس، آن را به `INSTALLED_APPS` در `settings.py` اضافه کنید:
INSTALLED_APPS = [
...
'rest_framework',
]
- طرح TokenAuthentication را به عنوان یک کلاس احراز هویت پیشفرض اضافه کنید (اختیاری، اما توصیه میشود):
در فایل `settings.py` خود، موارد زیر را اضافه کنید:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
}
این کار احراز هویت توکن را به طور سراسری در API شما اعمال میکند. `SessionAuthentication` برای تعامل مبتنی بر مرورگر گنجانده شده است، اما میتوانید آن را برای یک برنامه صرفاً مبتنی بر API حذف کنید.
- یک توکن برای هر کاربر ایجاد کنید:
میتوانید با افزودن یک کنترلکننده سیگنال، به طور خودکار هنگام ایجاد، برای کاربران توکن ایجاد کنید. یک فایل به نام `signals.py` در برنامه خود ایجاد کنید (به عنوان مثال، `users/signals.py`):
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
سپس، این فایل `signals.py` را در فایل `users/apps.py` خود در متد `ready` کلاس پیکربندی برنامه خود وارد کنید. مثال برای `users/apps.py`:
from django.apps import AppConfig
class UsersConfig(AppConfig):
default_auto_field = 'django.db.BigAutoField'
name = 'users'
def ready(self):
import users.signals
اکنون می توانید مدیریت tokes با استفاده از خط فرمان:
python manage.py drf_create_token <username>
- نماهای API خود را پیادهسازی کنید:
در اینجا یک مثال ساده از یک نما وجود دارد که به احراز هویت توکن نیاز دارد:
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
def get(self, request):
content = {
'message': 'Hello, ' + request.user.username + '! You are authenticated.',
}
return Response(content)
در این مثال، `authentication_classes` مشخص میکند که باید از احراز هویت توکن استفاده شود، و `permission_classes` مشخص میکند که فقط کاربران احراز هویتشده میتوانند به نما دسترسی داشته باشند.
- شامل نمای API ورود به سیستم:
شما همچنین به یک نقطه پایانی برای ایجاد توکن در ورود موفقیت آمیز نیاز دارید:
from django.contrib.auth import authenticate
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
@api_view(['POST'])
@permission_classes([AllowAny])
def login(request):
username = request.data.get('username')
password = request.data.get('password')
user = authenticate(username=username, password=password)
if user:
token, _ = Token.objects.get_or_create(user=user)
return Response({'token': token.key})
else:
return Response({'error': 'Invalid Credentials'}, status=status.HTTP_401_UNAUTHORIZED)
مزایای احراز هویت توکن
- سادگی: پیادهسازی و درک آسان.
- بدون حالت: هر درخواست توکن حاوی اطلاعاتی است که به آن اجازه میدهد به تنهایی بایستد.
معایب احراز هویت توکن
- وابستگی به پایگاه داده: برای هر درخواست برای تأیید اعتبار توکن، نیاز به جستجوی پایگاه داده دارد. این میتواند بر عملکرد، به ویژه در مقیاس بزرگ، تأثیر بگذارد.
- ابطال توکن: ابطال یک توکن مستلزم حذف آن از پایگاه داده است که میتواند پیچیده باشد.
- مقیاسپذیری: ممکن است به دلیل سربار پایگاه داده، مقیاسپذیرترین راه حل برای APIهای بزرگ و پر ترافیک نباشد.
احراز هویت JWT (JSON Web Token)
احراز هویت JWT یک رویکرد مدرنتر و پیچیدهتر است. JWT یک شی JSON فشرده و ایمن برای URL است که حاوی ادعاهایی در مورد کاربر است. این ادعاها به صورت دیجیتالی با استفاده از یک کلید مخفی یا یک جفت کلید عمومی/خصوصی امضا میشوند. هنگامی که یک کاربر وارد سیستم میشود، سرور یک JWT ایجاد میکند و آن را برای مشتری ارسال میکند. سپس مشتری این JWT را در هدر 'Authorization' درخواستهای بعدی قرار میدهد. سرور میتواند امضای JWT را بدون نیاز به دسترسی به پایگاه داده تأیید کند، و آن را به یک راه حل کارآمدتر و مقیاسپذیرتر تبدیل میکند.
پیادهسازی با DRF
DRF پشتیبانی داخلی از احراز هویت JWT را ارائه نمیدهد، اما چندین کتابخانه عالی وجود دارد که ادغام آن را آسان میکند. یکی از محبوبترین آنها `djangorestframework-simplejwt` است.
- `djangorestframework-simplejwt` را نصب کنید:
pip install djangorestframework-simplejwt
- تنظیمات DRF را پیکربندی کنید:
در فایل `settings.py` خود، موارد زیر را اضافه کنید:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
}
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
'ALGORITHM': 'HS256',
'SIGNING_KEY': settings.SECRET_KEY,
'VERIFYING_KEY': None,
'AUTH_HEADER_TYPES': ('Bearer',),
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
}
توضیح تنظیمات:
- `ACCESS_TOKEN_LIFETIME`: مدت زمان اعتبار توکن دسترسی (به عنوان مثال، 5 دقیقه).
- `REFRESH_TOKEN_LIFETIME`: مدت زمان اعتبار توکن تازهسازی (به عنوان مثال، 1 روز). توکنهای تازهسازی برای دریافت توکنهای دسترسی جدید بدون نیاز به ورود مجدد کاربر استفاده میشوند.
- `ROTATE_REFRESH_TOKENS`: اینکه آیا توکنهای تازهسازی پس از هر بار استفاده چرخانده شوند یا خیر.
- `BLACKLIST_AFTER_ROTATION`: اینکه آیا توکنهای تازهسازی قدیمی پس از چرخش در لیست سیاه قرار گیرند یا خیر.
- `ALGORITHM`: الگوریتم مورد استفاده برای امضای JWT (HS256 یک انتخاب رایج است).
- `SIGNING_KEY`: کلید مخفی مورد استفاده برای امضای JWT (به طور معمول کلید SECRET_KEY Django شما).
- `AUTH_HEADER_TYPES`: نوع هدر مجوز (به طور معمول "Bearer").
- شامل نماهای API ورود به سیستم و تازهسازی توکن:
`djangorestframework-simplejwt` نماهایی را برای به دست آوردن و تازهسازی توکنها ارائه میدهد. آنها را در `urls.py` خود قرار دهید:
from django.urls import path
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
`TokenObtainPairView` پس از احراز هویت موفقیتآمیز، توکنهای دسترسی و تازهسازی را ارائه میدهد. `TokenRefreshView` هنگام ارائه یک توکن تازهسازی معتبر، یک توکن دسترسی جدید ارائه میدهد.
- نماهای API خود را پیادهسازی کنید:
در اینجا یک مثال ساده از یک نما وجود دارد که به احراز هویت JWT نیاز دارد:
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.authentication import JWTAuthentication
class ExampleView(APIView):
authentication_classes = [JWTAuthentication]
permission_classes = [permissions.IsAuthenticated]
def get(self, request):
content = {
'message': 'Hello, ' + request.user.username + '! You are authenticated.',
}
return Response(content)
مشابه مثال احراز هویت توکن، `authentication_classes` مشخص میکند که باید از احراز هویت JWT استفاده شود، و `permission_classes` دسترسی را فقط به کاربران احراز هویتشده محدود میکند.
مزایای احراز هویت JWT
- مقیاسپذیری: برای تأیید اعتبار توکن، نیازی به جستجوی پایگاه داده نیست، که آن را مقیاسپذیرتر میکند.
- بدون حالت: JWT حاوی تمام اطلاعات لازم برای احراز هویت است.
- استانداردسازی شده: JWT یک استاندارد گسترده است که توسط بسیاری از کتابخانهها و پلتفرمها پشتیبانی میشود.
- دوستانه برای میکروسرویسها: برای معماریهای میکروسرویس مناسب است، زیرا سرویسها میتوانند JWTها را به طور مستقل تأیید کنند.
معایب احراز هویت JWT
- پیچیدگی: پیادهسازی آن پیچیدهتر از احراز هویت توکن است.
- اندازه توکن: JWTها میتوانند بزرگتر از توکنهای ساده باشند و به طور بالقوه استفاده از پهنای باند را افزایش دهند.
- ابطال توکن: ابطال یک JWT چالش برانگیز است. پس از صدور، تا زمان انقضای آن معتبر است. راه حلها شامل قرار دادن توکنهای باطلشده در لیست سیاه است که وابستگی به پایگاه داده را دوباره معرفی میکند.
استراتژیهای ابطال توکن
هر دو روش احراز هویت توکن و JWT به مکانیزمهایی برای ابطال دسترسی نیاز دارند. در اینجا نحوه برخورد با ابطال توکن آمده است:
ابطال احراز هویت توکن
با احراز هویت توکن، ابطال ساده است: به سادگی توکن را از پایگاه داده حذف کنید:
from rest_framework.authtoken.models import Token
try:
token = Token.objects.get(user=request.user)
token.delete()
except Token.DoesNotExist:
pass
ابطال احراز هویت JWT
ابطال JWT پیچیدهتر است زیرا خود توکن خودکفا است و برای تأیید اعتبار (در ابتدا) به جستجوی پایگاه داده متکی نیست. استراتژیهای رایج عبارتند از:
- لیست سیاه توکن: توکنهای باطلشده را در یک لیست سیاه ذخیره کنید (به عنوان مثال، یک جدول پایگاه داده یا یک کش Redis). قبل از تأیید اعتبار یک JWT، بررسی کنید که آیا در لیست سیاه وجود دارد یا خیر. `djangorestframework-simplejwt` پشتیبانی داخلی از لیست سیاه توکنهای تازهسازی را ارائه میدهد.
- زمان انقضای کوتاه: از زمان انقضای کوتاه توکن دسترسی استفاده کنید و برای دریافت توکنهای دسترسی جدید به طور مکرر به توکنهای تازهسازی تکیه کنید. این امر پنجره فرصت را برای استفاده از یک توکن در معرض خطر محدود میکند.
- چرخش توکنهای تازهسازی: توکنهای تازهسازی را بعد از هر بار استفاده بچرخانید. این کار هر بار توکنهای قدیمی را باطل میکند و از سرقت توکنها جلوگیری میکند.
OAuth2 و OpenID Connect
برای سناریوهای پیچیدهتر احراز هویت و مجوز، استفاده از OAuth2 و OpenID Connect را در نظر بگیرید. این استانداردها یک چارچوب قوی برای تفویض دسترسی به منابع بدون به اشتراک گذاشتن اعتبارنامهها ارائه میدهند. OAuth2 در درجه اول یک پروتکل مجوز است، در حالی که OpenID Connect بر روی OAuth2 ساخته میشود تا خدمات احراز هویت را ارائه دهد. چندین بسته Django، مانند `django-oauth-toolkit` و `django-allauth`، ادغام OAuth2 و OpenID Connect را در APIهای DRF شما تسهیل میکنند.
سناریوی مثال: یک کاربر میخواهد به یک برنامه شخص ثالث دسترسی به دادههای خود را که در API شما ذخیره شده است، اعطا کند. با OAuth2، کاربر میتواند بدون به اشتراک گذاشتن نام کاربری و رمز عبور خود، به برنامه مجوز دهد. در عوض، برنامه یک توکن دسترسی دریافت میکند که میتواند از آن برای دسترسی به دادههای کاربر در محدوده تعریف شده مجوزها استفاده کند.
انتخاب روش احراز هویت مناسب
بهترین روش احراز هویت به نیازهای خاص شما بستگی دارد:
- سادگی و سرعت پیادهسازی: احراز هویت توکن به طور کلی در ابتدا آسانتر پیادهسازی میشود.
- مقیاسپذیری: احراز هویت JWT برای APIهای پر ترافیک مقیاسپذیرتر است.
- الزامات امنیتی: حساسیت دادههای خود و سطح امنیتی مورد نیاز را در نظر بگیرید. OAuth2/OpenID Connect قویترین ویژگیهای امنیتی را ارائه میدهند اما نیاز به پیادهسازی پیچیدهتری دارند.
- معماری میکروسرویس: JWTها برای میکروسرویسها مناسب هستند، زیرا هر سرویس میتواند به طور مستقل توکنها را تأیید کند.
بهترین شیوهها برای احراز هویت API
- از HTTPS استفاده کنید: همیشه از HTTPS برای رمزگذاری ارتباطات بین مشتری و سرور استفاده کنید و از اعتبارنامهها در برابر استراق سمع محافظت کنید.
- اسرار را به طور ایمن ذخیره کنید: هرگز کلیدهای مخفی یا رمزهای عبور را در متن ساده ذخیره نکنید. از متغیرهای محیطی یا ابزارهای مدیریت پیکربندی ایمن استفاده کنید.
- پیادهسازی محدودیت نرخ: با پیادهسازی محدودیت نرخ برای محدود کردن تعداد درخواستهایی که یک مشتری میتواند در یک دوره زمانی مشخص انجام دهد، از API خود در برابر سوء استفاده محافظت کنید.
- تأیید اعتبار ورودی: تمام دادههای ورودی را به طور کامل تأیید اعتبار کنید تا از حملات تزریقی جلوگیری شود.
- نظارت و ثبت وقایع: API خود را برای فعالیتهای مشکوک نظارت کنید و رویدادهای احراز هویت را برای اهداف ممیزی ثبت کنید.
- بهروزرسانی منظم کتابخانهها: Django، DRF و کتابخانههای احراز هویت خود را بهروز نگه دارید تا از وصلههای امنیتی و بهبودها بهرهمند شوید.
- پیادهسازی CORS (به اشتراک گذاری منابع متقاطع): CORS را به درستی پیکربندی کنید تا فقط به دامنههای مورد اعتماد اجازه دهید از مرورگرهای وب به API شما دسترسی داشته باشند.
نتیجهگیری
انتخاب روش احراز هویت مناسب برای ایمنسازی APIهای DRF شما بسیار مهم است. احراز هویت توکن سادگی را ارائه میدهد، در حالی که احراز هویت JWT مقیاسپذیری و انعطافپذیری را فراهم میکند. درک مزایا و معایب هر روش، همراه با بهترین شیوهها برای امنیت API، شما را قادر میسازد تا APIهای قوی و ایمن بسازید که از دادهها و کاربران شما محافظت میکنند.
به یاد داشته باشید که نیازهای خاص خود را در نظر بگیرید و راه حلی را انتخاب کنید که به بهترین وجه امنیت، عملکرد و سهولت پیادهسازی را متعادل کند. OAuth2 و OpenID Connect را برای سناریوهای پیچیدهتر مجوز بررسی کنید.