FA-TOOLS — Header Component
کدهای آماده JWT در پایتون — احراز هویت

کدهای آماده JWT در پایتون — احراز هویت

خلاصه جامع: راهنمای احراز هویت با JWT در پایتون

JWT چیست؟

JSON Web Token یک استاندارد باز (RFC 7519) برای ایجاد توکن‌های دسترسی امن است که اطلاعات را به صورت فشرده و امضا شده بین طرفین انتقال می‌دهد. ایده‌آل برای احراز هویت بدون وضعیت (Stateless).

مراحل کلیدی در پایتون

  • نصب: `pip install PyJWT python-dotenv`
  • ایجاد توکن: رمزگذاری اطلاعات کاربر (Payload) با Secret Key.
  • اعتبارسنجی: رمزگشایی توکن، بررسی امضا و زمان انقضا.

نکات امنیتی

  • Secret Key قوی: همیشه از یک کلید بسیار پیچیده استفاده کنید.
  • زمان انقضا کوتاه: توکن‌ها را برای مدت کوتاهی معتبر نگه دارید.
  • HTTPS: همیشه از ارتباط امن (SSL/TLS) استفاده کنید.

JWT راه حلی قدرتمند برای احراز هویت مقیاس‌پذیر در برنامه‌های پایتونی است.

فهرست مطالب

کدهای آماده JWT در پایتون — احراز هویت — تصویر 1

در دنیای پرسرعت توسعه وب، احراز هویت کاربران یکی از مهم‌ترین چالش‌هاست. با ظهور معماری‌های میکروسرویس و API-Centric، روش‌های سنتی مبتنی بر Session با محدودیت‌هایی روبرو شده‌اند. اینجاست که JSON Web Token (JWT) به میدان می‌آید؛ یک راه حل قدرتمند و انعطاف‌پذیر برای احراز هویت بدون وضعیت که به سرعت در بین توسعه‌دهندگان پایتون محبوب شده است. در این مقاله جامع، ما به شما نشان می‌دهیم چطور می‌توانید از کدهای آماده JWT در پروژه‌های پایتونی خود برای پیاده‌سازی یک سیستم احراز هویت کارآمد استفاده کنید.

JWT چیست و چرا برای احراز هویت پایتون مهم است؟

کدهای آماده JWT در پایتون — احراز هویت — تصویر 2

JWT، که مخفف JSON Web Token است، یک استاندارد باز (RFC 7519) است که به شما اجازه می‌دهد اطلاعات را به صورت امن بین دو طرف به عنوان یک شیء JSON فشرده و امضا شده ارسال کنید. این توکن‌ها معمولاً برای احراز هویت (Authentication) و مجوزدهی (Authorization) استفاده می‌شوند.

اهمیت JWT در پایتون و سایر زبان‌ها از آنجا ناشی می‌شود که این توکن‌ها Stateless هستند. یعنی سرور نیازی به ذخیره اطلاعات نشست (Session) کاربر ندارد. وقتی کاربر با نام کاربری و رمز عبور خود وارد می‌شود، سرور یک JWT صادر می‌کند و آن را به کلاینت (معمولاً مرورگر یا اپلیکیشن موبایل) می‌فرستد. کلاینت این توکن را ذخیره می‌کند و در هر درخواست بعدی به سرور، آن را در هدر `Authorization` ارسال می‌کند. سرور با رمزگشایی و اعتبارسنجی توکن، هویت کاربر را شناسایی کرده و نیازی به مراجعه به پایگاه داده برای هر درخواست ندارد.

ساختار JWT

یک توکن JWT از سه بخش اصلی تشکیل شده که با نقطه (.) از هم جدا می‌شوند:

  • Header (سربرگ): شامل نوع توکن (JWT) و الگوریتم هش‌گذاری (مثلاً HS256 یا RS256).
  • Payload (محتوا): اطلاعاتی که می‌خواهید منتقل کنید (Claims)؛ مثل شناسه کاربر، نقش، زمان انقضا و… . مراقب باشید اطلاعات حساس در اینجا قرار ندهید، چون Payload فقط Base64-encoded است و رمزگذاری نشده.
  • Signature (امضا): این بخش برای تأیید اعتبار توکن استفاده می‌شود. سربرگ، محتوا و یک Secret Key روی سرور با الگوریتم مشخص شده هش می‌شوند تا Signature تولید شود.

نتیجه نهایی شبیه به این است: xxxxx.yyyyy.zzzzz

معماری احراز هویت با JWT در پایتون

کدهای آماده JWT در پایتون — احراز هویت — تصویر 3

معماری احراز هویت با JWT نسبتاً ساده و مستقیم است. در اینجا یک فلو چارت کلی از این فرآیند را می‌بینید:

  1. ورود کاربر (User Login): کاربر نام کاربری و رمز عبور خود را به سرور ارسال می‌کند.
  2. اعتبارسنجی مدارک (Credentials Validation): سرور مدارک کاربر را در پایگاه داده اعتبارسنجی می‌کند.
  3. ایجاد JWT (JWT Creation): در صورت موفقیت‌آمیز بودن احراز هویت، سرور یک JWT شامل اطلاعات کاربر (مثل `user_id`, `role`) و زمان انقضا ایجاد می‌کند و آن را با یک `Secret Key` امضا می‌کند.
  4. ارسال JWT به کلاینت (Send JWT to Client): سرور JWT امضا شده را به عنوان پاسخ به درخواست ورود به کلاینت (مثلاً در هدر `Authorization` یا بدنه پاسخ) برمی‌گرداند.
  5. ذخیره و ارسال JWT توسط کلاینت (Client Stores & Sends JWT): کلاینت توکن را ذخیره می‌کند (مثلاً در Local Storage مرورگر یا حافظه اپلیکیشن) و در هر درخواست بعدی به منابع محافظت‌شده، آن را در هدر `Authorization` به سرور می‌فرستد (با پیشوند `Bearer`).
  6. اعتبارسنجی JWT توسط سرور (Server Validates JWT): سرور توکن را از درخواست کلاینت دریافت کرده، امضای آن را با استفاده از همان `Secret Key` اعتبارسنجی می‌کند و زمان انقضای توکن را بررسی می‌کند.
  7. دسترسی به منابع (Resource Access): اگر توکن معتبر باشد، سرور اجازه دسترسی به منابع درخواستی را می‌دهد؛ در غیر این صورت، خطای “عدم دسترسی” یا “توکن نامعتبر” برمی‌گرداند.

نصب کتابخانه‌های مورد نیاز

برای کار با JWT در پایتون، کتابخانه PyJWT بهترین و استانداردترین گزینه است. همچنین برای مدیریت ایمن `Secret Key`، استفاده از python-dotenv توصیه می‌شود. اگر با یک فریمورک وب مانند Flask کار می‌کنید، آن را هم نصب کنید.

pip install PyJWT python-dotenv Flask

Flask در اینجا فقط یک مثال است؛ شما می‌توانید این منطق را در Django، FastAPI یا هر فریمورک دیگری پیاده‌سازی کنید.

ایجاد توکن JWT: کدهای آماده گام به گام

حالا به سراغ کدهای آماده برای ایجاد توکن JWT می‌رویم.

گام ۱: تعریف Secret Key امن

Secret Key یکی از مهم‌ترین اجزای امنیت JWT است. این کلید باید بسیار پیچیده، طولانی و محرمانه باشد و هرگز در کد منبع یا سیستم کنترل نسخه (مثل Git) ذخیره نشود. بهترین روش استفاده از متغیرهای محیطی است. یک فایل `.env` در ریشه پروژه خود ایجاد کنید:

# .env
SECRET_KEY="super_secret_and_long_random_key_that_no_one_can_guess_1234567890"
# شما باید یک کلید تصادفی و بسیار قوی برای پروژه واقعی خود تولید کنید.

سپس در کد پایتون خود، این کلید را بارگذاری کنید:

import os
from datetime import datetime, timedelta
import jwt
from dotenv import load_dotenv

load_dotenv()  # بارگذاری متغیرهای محیطی از فایل .env

SECRET_KEY = os.getenv("SECRET_KEY")
# مطمئن شوید که کلید مخفی وجود دارد، در غیر این صورت یک خطا ایجاد کنید.
if not SECRET_KEY:
    raise ValueError("SECRET_KEY not found in environment variables")

گام ۲: تابع ساخت توکن (Encoding)

این تابع یک توکن JWT را با استفاده از اطلاعات کاربر، زمان انقضا و `Secret Key` تولید می‌کند.

def create_jwt_token(user_id: int, roles: list, expires_delta: timedelta = None):
    if expires_delta is None:
        expires_delta = timedelta(minutes=30) # توکن به صورت پیش‌فرض ۳۰ دقیقه اعتبار دارد

    expire = datetime.utcnow() + expires_delta
    payload = {
        "user_id": user_id,
        "roles": roles,
        "exp": expire,  # زمان انقضا
        "iat": datetime.utcnow(),  # زمان صدور توکن
    }
    encoded_jwt = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
    return encoded_jwt

# مثال استفاده:
token = create_jwt_token(user_id=123, roles=["admin", "user"])
print("Generated JWT:", token)

گام ۳: افزودن توکن به پاسخ (Response)

معمولاً پس از احراز هویت موفق، توکن به عنوان بخشی از پاسخ JSON به کلاینت ارسال می‌شود. یا در هدر `Authorization` (هرچند کمتر رایج است) یا در بدنه پاسخ.

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/login', methods=['POST'])
def login():
    username = request.json.get('username', None)
    password = request.json.get('password', None)

    # در اینجا منطق اعتبارسنجی کاربر (مثلاً از پایگاه داده) را قرار دهید.
    # برای مثال:
    if username == "testuser" and password == "password123":
        user_id = 1
        roles = ["user"]
        access_token = create_jwt_token(user_id=user_id, roles=roles)
        return jsonify(access_token=access_token), 200
    return jsonify({"msg": "Bad username or password"}), 401

# برای اجرا:
if __name__ == '__main__':
    app.run(debug=True)

اعتبارسنجی توکن JWT: کدهای آماده گام به گام

پس از اینکه کلاینت توکن را دریافت کرد، باید آن را در هر درخواست به سرور برگرداند تا هویتش تایید شود.

گام ۱: دریافت توکن از درخواست (Request)

توکن معمولاً در هدر `Authorization` با پیشوند `Bearer` ارسال می‌شود: `Authorization: Bearer `.

from flask import request

def get_jwt_from_request():
    auth_header = request.headers.get('Authorization')
    if not auth_header:
        return None
    # انتظار داریم توکن به شکل "Bearer " باشد
    parts = auth_header.split()
    if len(parts) == 2 and parts[0].lower() == 'bearer':
        return parts[1]
    return None

گام ۲: تابع اعتبارسنجی (Decoding)

این تابع توکن را رمزگشایی و اعتبارسنجی می‌کند. در صورت نامعتبر بودن توکن (مثلاً امضای اشتباه یا انقضای زمان)، یک استثنا (Exception) پرتاب می‌شود.

def decode_jwt_token(token: str):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        return payload
    except jwt.ExpiredSignatureError:
        # توکن منقضی شده است
        return {"error": "Token has expired"}
    except jwt.InvalidTokenError:
        # توکن نامعتبر است (مثلاً امضا اشتباه)
        return {"error": "Invalid token"}
    except Exception as e:
        # خطاهای دیگر
        return {"error": str(e)}

# مثال استفاده:
decoded_payload = decode_jwt_token(token) # استفاده از توکن تولید شده در گام قبلی
print("Decoded JWT Payload:", decoded_payload)

گام ۳: محافظت از مسیرها (Protected Routes)

برای محافظت از مسیرها، می‌توانیم یک دکوراتور (Decorator) در Flask ایجاد کنیم که قبل از اجرای تابع اصلی مسیر، توکن را اعتبارسنجی کند.

from functools import wraps

def jwt_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        token = get_jwt_from_request()
        if not token:
            return jsonify({"msg": "JWT token is missing!"}), 401

        payload = decode_jwt_token(token)
        if "error" in payload:
            return jsonify({"msg": payload["error"]}), 403

        # توکن معتبر است، اطلاعات کاربر را به تابع اصلی پاس می‌دهیم
        request.current_user = payload["user_id"]
        request.current_roles = payload["roles"]

        return f(*args, **kwargs)
    return decorated_function

@app.route('/protected', methods=['GET'])
@jwt_required
def protected_route():
    # فقط کاربرانی که توکن JWT معتبر دارند می‌توانند به اینجا دسترسی داشته باشند
    return jsonify({
        "msg": f"Hello, user {request.current_user} with roles {request.current_roles}!"
    }), 200

مدیریت توکن‌های رفرش (Refresh Tokens)

استفاده از JWT با زمان انقضای کوتاه برای `Access Token` یک روش امنیتی خوب است. اما کاربران دوست ندارند هر چند دقیقه یکبار دوباره لاگین کنند. اینجاست که Refresh Tokens وارد می‌شوند.

یک `Refresh Token` یک توکن با عمر طولانی‌تر است که برای گرفتن `Access Token` جدید (زمانی که `Access Token` منقضی می‌شود) استفاده می‌شود. این توکن معمولاً در یک پایگاه داده ذخیره می‌شود و می‌تواند در صورت نیاز باطل (revoked) شود.

نحوه کارکرد Refresh Token

  • پس از ورود موفق، سرور هم Access Token (کوتاه مدت) و هم Refresh Token (بلند مدت) را صادر می‌کند.
  • کلاینت `Access Token` را برای درخواست‌های محافظت‌شده ارسال می‌کند.
  • وقتی `Access Token` منقضی شد، کلاینت `Refresh Token` را به یک endpoint خاص (مثلاً `/refresh_token`) ارسال می‌کند.
  • سرور `Refresh Token` را اعتبارسنجی می‌کند (بررسی در پایگاه داده) و در صورت معتبر بودن، یک Access Token جدید صادر کرده و به کلاینت برمی‌گرداند.

پیاده‌سازی کامل Refresh Token نیاز به ذخیره‌سازی در دیتابیس دارد که فراتر از کدهای آماده اولیه JWT است، اما مفهوم آن حیاتی است.

امنیت JWT: نکات مهم و بهترین روش‌ها

هرچند JWT یک راهکار قوی است، اما مانند هر سیستم امنیتی دیگری، نیاز به رعایت بهترین روش‌ها دارد تا از آسیب‌پذیری‌ها جلوگیری شود.

  • Secret Key بسیار قوی: همانطور که قبلاً اشاره شد، کلید مخفی شما باید طولانی، پیچیده و کاملاً تصادفی باشد. آن را از طریق متغیرهای محیطی یا سرویس‌های مدیریت کلید امنیتی (مثل HashiCorp Vault) مدیریت کنید.
  • زمان انقضا کوتاه (Exp): `Access Token`ها را برای مدت زمان کوتاه (مثلاً ۱۵ تا ۶۰ دقیقه) معتبر نگه دارید. این کار ریسک سوءاستفاده از توکن‌های دزدیده شده را کاهش می‌دهد.
  • استفاده از HTTPS/SSL/TLS: همیشه اطمینان حاصل کنید که تمام ارتباطات بین کلاینت و سرور از طریق HTTPS انجام می‌شود تا توکن‌ها در حین انتقال رمزگذاری شده و از حملات Man-in-the-Middle محافظت شوند.
  • عدم ذخیره اطلاعات حساس در Payload: به یاد داشته باشید که Payload توکن فقط Base64-encoded است و رمزگذاری نشده است. هر اطلاعاتی که در آن قرار می‌دهید برای هر کسی قابل مشاهده است. از قرار دادن رمز عبور، اطلاعات کارت اعتباری یا هر داده شخصی حساس خودداری کنید.
  • مکانیزم ابطال توکن (Token Revocation): JWTها به طور طبیعی قابلیت ابطال ندارند (به دلیل stateless بودن). برای باطل کردن یک توکن (مثلاً هنگام خروج کاربر یا تغییر رمز عبور)، باید یک Blacklist یا Blocklist در سمت سرور پیاده‌سازی کنید. این لیست حاوی شناسه (JTI) توکن‌هایی است که باید باطل شوند و سرور قبل از اعتبارسنجی هر توکن، آن را با این لیست مقایسه می‌کند.
  • مکان ذخیره سازی توکن در کلاینت:
    • Local Storage/Session Storage: ساده است اما در برابر حملات XSS (Cross-Site Scripting) آسیب‌پذیر است.
    • HTTP-only Cookies: مقاومت بیشتری در برابر XSS دارد، اما در برابر حملات CSRF (Cross-Site Request Forgery) آسیب‌پذیر است. باید از مکانیزم‌های ضد-CSRF همراه با آن استفاده شود.
  • بررسی الگوریتم: مطمئن شوید که سرور شما همیشه از همان الگوریتم هش‌گذاری که توکن با آن صادر شده، برای اعتبارسنجی استفاده می‌کند. حمله‌ای وجود دارد که به آن “None Algorithm” گفته می‌شود که در آن مهاجم می‌تواند توکن را بدون امضا ارسال کند. کتابخانه PyJWT به طور خودکار این حمله را پوشش می‌دهد، اما همیشه هوشیار باشید.

مقایسه JWT با Session-based Authentication

بیایید نگاهی به تفاوت‌های اصلی بین JWT و احراز هویت مبتنی بر Session بیندازیم:

ویژگی JWT (JSON Web Token)
وضعیت (State) Stateless: سرور اطلاعات نشست را ذخیره نمی‌کند. توکن حاوی تمام اطلاعات لازم است.
مقیاس‌پذیری (Scalability) عالی برای میکروسرویس‌ها و برنامه‌های توزیع‌شده، چون نیازی به Session Stickiness نیست.
مدیریت Cross-Domain ذاتی Cross-Domain است، چون توکن می‌تواند به راحتی بین دامنه‌های مختلف ارسال شود (با رعایت CORS).
ابطال توکن (Revocation) ذاتاً ندارد؛ نیاز به پیاده‌سازی Blacklist یا Refresh Token است.
سربار سرور (Server Overhead) کمتر، چون نیازی به جستجو در دیتابیس یا حافظه برای هر درخواست نیست.

عیب‌یابی سریع (Troubleshooting)

در حین کار با JWT ممکن است با خطاهای رایجی روبرو شوید. در اینجا به برخی از آن‌ها و راه‌حلشان اشاره می‌کنیم:

  • ۱. `jwt.exceptions.InvalidSignatureError`

    مشکل: امضای توکن نامعتبر است. این یعنی توکن با `Secret Key` دیگری امضا شده یا دستکاری شده است.

    راه‌حل: مطمئن شوید که `SECRET_KEY` مورد استفاده برای رمزگشایی توکن دقیقاً همان `SECRET_KEY` است که برای ایجاد توکن استفاده شده است. چک کنید که هیچ فضای خالی اضافی یا تغییر کوچکی در آن وجود ندارد.

  • ۲. `jwt.exceptions.ExpiredSignatureError`

    مشکل: توکن منقضی شده است. Payload شامل `exp` (expiration time) است و زمان فعلی از آن گذشته است.

    راه‌حل: از کلاینت بخواهید یک توکن جدید درخواست کند (معمولاً با استفاده از `Refresh Token`). مطمئن شوید که زمان سیستم سرور به درستی تنظیم شده باشد. برای تست، می‌توانید زمان `exp` را در تابع `create_jwt_token` افزایش دهید.

  • ۳. `jwt.exceptions.InvalidTokenError`

    مشکل: توکن فرمت نامعتبری دارد، ممکن است Header یا Payload مشکل داشته باشد.

    راه‌حل: مطمئن شوید که توکن دریافتی از کلاینت یک رشته JWT صحیح و کامل (سه بخش جدا شده با نقطه) است. بررسی کنید که هیچ کاراکتر اضافی یا ناقصی در آن وجود ندارد.

  • ۴. توکن در Header `Authorization` یافت نمی‌شود.

    مشکل: تابع `get_jwt_from_request()` توکن را دریافت نمی‌کند.

    راه‌حل:

    • مطمئن شوید کلاینت هدر `Authorization` را با فرمت `Bearer ` ارسال می‌کند.
    • بررسی کنید که فریمورک وب شما (مثلاً Flask) هدر `Authorization` را به درستی parse می‌کند. گاهی اوقات وب سرورها (مانند Nginx یا Apache) این هدر را به صورت پیش‌فرض پاس نمی‌دهند و نیاز به تنظیمات خاص دارند.

سوالات متداول (FAQ)

آیا JWT امن است؟

بله، JWT در صورت پیاده‌سازی صحیح، بسیار امن است. اما امنیت آن به شدت به محرمانه ماندن Secret Key، استفاده از HTTPS و مدیریت صحیح زمان انقضای توکن بستگی دارد. فراموش نکنید که Payload رمزگذاری نمی‌شود و فقط Base64-encoded است، پس اطلاعات حساس نباید در آن قرار بگیرند.

آیا می‌توانیم JWT را در سمت کلاینت ذخیره کنیم؟

بله، JWT باید در سمت کلاینت ذخیره شود تا در درخواست‌های بعدی به سرور ارسال شود. معمولاً در Local Storage، Session Storage یا HTTP-only Cookies ذخیره می‌شود. هر روش مزایا و معایب امنیتی خود را دارد. HTTP-only Cookies در برابر حملات XSS امن‌تر هستند، اما در برابر CSRF باید تمهیدات خاصی اندیشید. برای Local Storage، باید از حملات XSS کاملاً محافظت شود.

JWT برای کدام نوع برنامه‌ها مناسب‌تر است؟

JWT به ویژه برای APIها، میکروسرویس‌ها، و برنامه‌هایی که نیاز به Single Sign-On (SSO) دارند بسیار مناسب است. از آنجایی که Stateless است، مقیاس‌پذیری بالایی دارد و نیاز به نگهداری وضعیت نشست در سرور را از بین می‌برد.

تفاوت `HS256` و `RS256` چیست؟

این‌ها الگوریتم‌های امضای JWT هستند:

  • HS256 (HMAC with SHA-256): از یک Secret Key مشترک برای امضا و اعتبارسنجی استفاده می‌کند. این الگوریتم Symmetric است و برای سناریوهایی که فقط یک نهاد (سرور شما) توکن را صادر و اعتبارسنجی می‌کند، مناسب است.
  • RS256 (RSA with SHA-256): از یک جفت کلید عمومی/خصوصی استفاده می‌کند. کلید خصوصی برای امضا و کلید عمومی برای اعتبارسنجی توکن به کار می‌رود. این الگوریتم Asymmetric است و برای سناریوهایی که چندین سرویس (مثل Identity Provider) توکن را صادر می‌کنند و سرویس‌های دیگر فقط آن را اعتبارسنجی می‌کنند، ایده‌آل است.

 

Table of Contents

آخرین نوشته‌ها