2 خرداد 1404

احرازهویت با جنگو همهچیز دربارهی احراز هویت با کوکی و JWT
چرا احراز هویت مهم است ؟
احراز هویت فرآیندی است که هنگام ورود به یک وبسایت یا برنامه اجرا میشود. این سیستمها ابتدا هویت شما را تأیید میکنند تا مطمئن شوند که شما اجازهی دسترسی به دادهها یا سرویسهای شخصی خود را دارید. از ورود به رسانههای اجتماعی گرفته تا بانکداری آنلاین، احراز هویت نقشی کلیدی در حفظ امنیت و حریم خصوصی زندگی دیجیتال ما ایفا میکند.
در ادامه این آموزش، به بررسی مفهوم احراز هویت خواهیم پرداخت و شما را با روشهای مختلف آن آشنا خواهیم کرد. همچنین تفاوتهای میان احراز هویت با کوکی و JWT را توضیح داده و در فریمورک جنگو به صورت عملی بررسی خواهیم کرد.
دسترسی سریع
احراز هویت چیست ؟
به زبان ساده، به هر فرآیندی که اطلاعات یک فرد رو تایید کند احراز هویت گفته میشود.
مثلاً وقتی وارد حساب کاربریتان در یک سایت یا یک اپلیکیشن میشوید، سیستم بررسی میکند که نام کاربری و رمز عبور شما درست باشد تا مطمئن شود فردی غیرمجاز دسترسی پیدا نکرده است. این فرآیند میتواند با رمز عبور و یا کد پیامکی انجام شود.
بدون احراز هویت، هر کسی میتوانست وارد حساب شما شود و اطلاعات شخصیتان را تغییر دهد یا سوءاستفاده کند. به همین دلیل است که این فرآیند یکی از پایههای اصلی امنیت دیجیتال محسوب میشود!
آموزش مفهوم و پشت پرده احراز هویت
1️⃣ ارسال درخواست ورود
- کاربران اطلاعات خود مانند شمارهتلفن، نام کاربری و رمز عبور خود را وارد میکنند
- این دادهها بهصورت رمزگذاریشده به سرور ارسال میشوند تا از سرقت اطلاعات جلوگیری شود.
2️⃣ بررسی صحت اطلاعات وارد شده
- سرور اطلاعات دریافتی را پردازش میکند تا اطلاعات صحیح باشند.
- سپس اطلاعات شما رمزگذاریشده و در پایگاه داده ذخیره میشود (اگر از قبل حساب دارید فقط صحت اطلاعات چک میشود) و برای شما یک توکن امنیتی صادر میشود.
- توکن صادرشده به کاربران اجازه میدهد تا بدون نیاز به ورود مجدد، به سرویسها دسترسی داشته باشند. این توکن دارای مدت اعتبار محدود است و پس از پایان تاریخ مصرف، نیاز به احراز هویت مجدد خواهد بود.
3️⃣ لاگین مجدد بدون وارد کردن اطلاعات دوباره
- حالا با استفادهی یکی از دو روش Session Base و یا Token Base اطلاعات رمزگذاریشده را در مرورگر ذخیره میکنیم ( آموزش ذخیره داده ها در مرورگر ).
- در هر بازدید از صفحات وب، مرورگر بهصورت خودکار اطلاعات لازم مانند توکن احراز هویت یا شناسه نشست را به سرور ارسال میکند تا وضعیت ورود کاربر تأیید شود.
🔐 برنامهنویسان حرفهای متعهد به حفظ حریم خصوصی کاربران هستند و هرگز رمز عبور را بهصورت رمزگذارینشده ذخیره نمیکنند.
اگر به دنبال طراحی سایت حرفهای و امن هستید، همین الان با 0912-845-5626 تماس بگیرید و پروژه خود را به سطح بالاتری ببرید!
احراز هویت با Session و کوکی ها (Stateful authentication)
پس از وارد کردن اطلاعات و ورود موفق به اپلیکیشن یا وبسایت یک Session ID توسط سرور در کوکی ذخیره میشود.
برای افزایش امنیت و جلوگیری از حملات MITM و Session Hijacking، ذخیرهی Session ID در کوکی باید از سمت سرور انجام شود. همچنین، لازم است فلگهای امنیتی مانند Secure و HttpOnly فعال شوند تا از دسترسیهای غیرمجاز محافظت شود.
Session ID ذخیرهشده در کوکی با هر درخواست بهصورت خودکار به سرور ارسال میشود و سرور بر اساس آن وضعیت احراز هویت کاربر را تأیید یا رد میکند.
احراز هویت Session Base ( با کوکی ها ) در جنگو
جنگو یک سیستم احراز هویت داخلی دارد که بسیاری از کارهای پیچیده را بهصورت خودکار انجام میدهد. جنگو کار را آسان کرده، اما همچنان باید تنظیمات و شخصیسازیهای مورد نیاز را انجام دهید
1️⃣ ایجاد پروژه و تنظیمات اولیه Django
ابتدا پروژه رو راه اندازی میکنیم و سپس تنظیمات آن را درست میکنیم.
terminal
pip install django
django-admin startproject core .
python manage.py startapp accounts
settings.py
INSTALLED_APPS = [
...
'django.contrib.sessions',
'accounts',
]
...
SESSION_ENGINE = "django.contrib.sessions.backends.db"
SESSION_COOKIE_SECURE = True
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_COOKIE_AGE = 3600
2️⃣ راه اندازی View برای لاگین
from django.contrib.auth import authenticate, login, logoutfrom django.shortcuts import render, redirectdef user_login(request):if request.method == "POST":username = request.POST['username']password = request.POST['password']user = authenticate(request, username=username, password=password)if user is not None:login(request, user) # ایجاد نشست برای کاربرreturn redirect('dashboard') # هدایت به صفحه داشبوردelse:return render(request, 'login.html', {'error': 'نام کاربری یا رمز عبور نادرست است'})return render(request, 'login.html')
📌 تابع authenticate
این تابع 3 ورودی دریافت میکند. اولی request هست، دومی نام کاربری فرد و سومی رمزعبور فرد.
این تابع بررسی میکند اگر کاربری با این مشخصات در پایگاه داده وجود دارد یک User Object بر میگرداند در غیر این صورت مقدار None میدهد.
📌 تابع login
این تابع بعد از تأیید اعتبار کاربر، یک نشست (Session) برای او ایجاد میکند. باعث میشود که کاربر در کل درخواستهای بعدی، لاگین باقی بماند.
3️⃣ راه اندازی View برای رجیستر
from django.contrib.auth.forms import UserCreationFormfrom django.contrib.auth import loginfrom django.shortcuts import render, redirectdef register(request):if request.method == "POST":form = UserCreationForm(request.POST)if form.is_valid():user = form.save()login(request, user) # ورود خودکار پس از ثبتنامreturn redirect('dashboard')else:form = UserCreationForm()return render(request, "register.html", {"form": form})
این قطعه کد برای این است که مشخصات رمزگذاریشدهی فرد رو در پایگاه داده ذخیره کنیم و سپس فرد رو احراز هویت کنیم.
4️⃣ تست احراز هویت و دسترسی به اطلاعات کاربر
وقتی که کاربر احراز شده به طور خودکار به مشخصات کاربر در request دسترسی داریم.
views.py
def dashboard(request):
is_user = request.user.is_authenticated # آیا فرد احراز هست
username = request.user.username # نام کاربری فرد
email = request.user.email # ایمیل فرد
return render(request,"dashboard.html",{"user": request.user})
احراز هویت JWT در جنگو (Stateless authentication)
JSON Web Token (JWT) یک روش امن برای احراز هویت و تبادل اطلاعات بین دو طرف است.
توکن در پایگاه داده ذخیره نمیشود، بلکه فقط اطلاعات هویتی فرد در پایگاه داده نگهداری میشود. پس از احراز هویت موفق، سرور یک توکن امضاشده به کلاینت ارسال میکند. کلاینت این توکن را در درخواستهای بعدی ارسال میکند و سرور صحت امضا را بررسی کرده و کاربر را تأیید یا رد میکند.
برخلاف روش کوکیها که بهصورت خودکار با هر درخواست به سرور ارسال میشدند، در این روش کلاینت هر زمان که به مشخصات کاربر نیاز داشته باشد، باید یک درخواست HTTP همراه با توکن به سرور ارسال کند تا احراز هویت انجام شود.
در احراز هویت JWT معمولا دو نوع توکن refresh token , access token استفاده میشود، که هرکدام نقش متفاوتی دارند.
🔹 Access Token
- توکن اصلی برای احراز هویت و دسترسی به منابع محافظتشده
- مدت اعتبار کوتاه (چند دقیقه تا یک ساعت)
- در هر درخواست به سرور ارسال میشود (معمولاً در هدر Authorization)
- پس از منقضی شدن، دیگر قابل استفاده نیست و باید یک توکن جدید دریافت شود
- در مرورگر یا حافظهی کلاینت ذخیره میشود، ترجیا در localstorage ذخیره نشود.
🔹 Refresh Token
- برای دریافت یک Access Token جدید بدون نیاز به ورود مجدد استفاده میشود
- مدت اعتبار طولانیتری دارد (چند ساعت، روز یا حتی هفته)
- در پایگاه داده یا یک فضای امن ذخیره میشود تا امکان لغو آن وجود داشته باشد
- بهصورت عمومی در درخواستها ارسال نمیشود، بلکه فقط برای درخواستهای بازتولید توکن استفاده میشود
احراز هویت JWT با جنگو
جنگو بهصورت پیشفرض قابلیت ایجاد و مدیریت API و توکنهای احراز هویت را ندارد. برای این منظور، از دو پکیج قدرتمند djangorestframework و djangorestframework_simplejwt استفاده میکنیم که بر روی جنگو قرار میگیرند و امکان مدیریت API و احراز هویت با JWT را فراهم میکنند.
1️⃣ نصب پکیجهای مورد نیاز و تنظیمات اولیه
terminal
pip install djangorestframework djangorestframework_simplejwt
settings.py
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework_simplejwt',
]
...
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
این تنظیمات باعث میشود که تمام درخواستهای API نیاز به احراز هویت با JWT داشته باشند.
2️⃣ تعریف url برای متدهای تعریف شده
کلاسهای TokenObtainPairView و TokenRefreshView از پیش تعریف شدهاند و فرآیند احراز هویت کاربران موجود و تمدید توکن را سادهتر میکنند. با استفاده از این کلاسها، بدون نیاز به پیادهسازی دستی، میتوان توکنهای JWT را مدیریت کرد.
from django.urls import pathfrom rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshViewurlpatterns = [path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # دریافت Access Token و Refresh Tokenpath('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # دریافت Access Token جدید]
3️⃣ ساخت view اختصاصی برای ثبت نام
کلاسهای TokenObtainPairView و TokenRefreshView تنها برای کاربران موجود طراحی شدهاند و توانایی ثبتنام کاربران جدید را ندارند. برای احراز هویت کاربری که از قبل در سیستم وجود ندارد، باید یک متد اختصاصی برای ثبتنام ایجاد کنیم.
from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework_simplejwt.tokens import RefreshTokenfrom django.contrib.auth.models import Userclass RegisterView(APIView):def post(self, request):username = request.data.get("username")password = request.data.get("password")if User.objects.filter(username=username).exists():return Response({"error": "نام کاربری قبلاً ثبت شده است"}, status=400)user = User.objects.create_user(username=username, password=password)refresh = RefreshToken.for_user(user)return Response({"access_token": str(refresh.access_token),"refresh_token": str(refresh)})
4️⃣ تست احراز هویت و دسترسی به اطلاعات کاربر
djangorestframework_simplejwt همانند سیستم احراز هویت داخلی جنگو، آبجکت user را در request قرار میدهد.
from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework.permissions import IsAuthenticatedclass DashboardView(APIView):#داشبورد فقط برای کاربران لاگینشدهpermission_classes = [IsAuthenticated]if user.is_staff:role = "ادمین"else:role = "کاربر معمولی"def get(self, request):user = request.userdashboard_data = {"username": user.username,"email": user.email,"joined_at": user.date_joined.strftime('%Y-%m-%d'),"role": role,}return Response(dashboard_data)
5️⃣ نحوه ارسال درخواست های http به سرور
🔹 ارسال درخواست برای احراز هویت
async function getTokens(username, password) {const response = await fetch("http://127.0.0.1:8000/api/token/", {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({ username, password })});const data = await response.json();if (response.ok) {console.log("Access Token:", data.access); // توکن رو ذخیره کنconsole.log("Refresh Token:", data.refresh); // توکن رو ذخیره کن} else {console.error("Error:", data.error);}}
🔹 ارسال درخواست تمدید توکن
async function refreshAccessToken(refreshToken) {const response = await fetch("http://127.0.0.1:8000/api/token/refresh/", {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({ refresh: refreshToken })});const data = await response.json();if (response.ok) {console.log("New Access Token:", data.access);return data.access;} else {console.error("Error:", data.error);}}
🔹 چک کردن احراز هویت و دریافت اطلاعات کاربر
هنگام استفاده از JWT Authentication، برای دسترسی به APIهای محافظتشده باید Access Token را در هدر Authorization ارسال کنیم. این توکن باید همراه با کلمهی Bearer باشد تا سرور بتواند آن را تشخیص دهد.
async function fetchDashboard(accessToken) {const response = await fetch("http://127.0.0.1:8000/api/dashboard/", {method: "GET",headers: { "Authorization": `Bearer ${accessToken}` }});const data = await response.json();if (response.ok) {console.log("Dashboard Data:", data);return data;} else {console.error("Unauthorized:", data.error);}}
نتیجه گیری
در این آموزش، شما با مفاهیم پایهای احراز هویت مبتنی بر JWT و کوکی ها در جنگو آشنا شدید و یاد گرفتید چگونه Access Token و Refresh Token را مدیریت کنید. همچنین روشهای ارسال درخواستها از کلاینت، بررسی احراز هویت و محافظت از API را مرور کردیم.
اکنون، شما میتوانید با تمرین بیشتر و پیشرفت در کار، فرآیند احراز هویت را یک مرحله بالاتر ببرید و براساس نیازتان فرآیند را سفارشیسازی کنید.