احراز هویت حرفه‌ای با JWT در فلسک

احراز هویت حرفه‌ای با JWT در فلسک

احراز هویت با jwt
برنامه نویسی توسعه وب

احراز هویت حرفه‌ای با JWT در فلسک

در بخش اول، با ساختار داخلی JWT و نحوه ساخت دستی آن آشنا شدیم. اما در پروژه‌های واقعی، پیاده‌سازی دستی توکن‌ها به دلایل امنیتی و پیچیدگی‌های مربوط به کدگذاری (Encoding) و مدیریت زمان، توصیه نمی‌شود. در این بخش، از کتابخانه استاندارد و قدرتمند PyJWT استفاده می‌کنیم تا یک سیستم احراز هویت کامل و امن را در فریم‌ورک فلسک پیاده‌سازی کنیم.

نصب پیش‌نیازها

برای شروع، شما نیاز به نصب کتابخانه PyJWT دارید. اگر هنوز فلسک را نصب نکرده‌اید، آن را نیز اضافه کنید. دستور زیر را در ترمینال اجرا کنید:

pip install Flask PyJWT

تنظیمات اولیه و کلید مخفی

امنیت JWT به شدت به “کلید مخفی” (Secret Key) وابسته است. این کلید باید طولانی، پیچیده و کاملاً محرمانه باشد. در فلسک، معمولاً این کلید را در تنظیمات برنامه قرار می‌دهیم.

from flask import Flask, request, jsonify
import jwt
import datetime
from functools import wraps

app = Flask(__name__)

# کلید مخفی برای امضای توکن‌ها
# در محیط واقعی، این مقدار باید از متغیرهای محیطی (Environment Variables) خوانده شود
app.config['SECRET_KEY'] = 'this_is_a_very_secure_secret_key_1234567890'

۱. ایجاد مسیر ورود (Login) و تولید توکن

اولین قدم، ایجاد یک مسیر است که کاربر نام کاربری و رمز عبور خود را ارسال می‌کند. اگر اطلاعات صحیح باشد، یک توکن JWT تولید شده و به کاربر بازگردانده می‌شود. این توکن باید شامل اطلاعات هویتی کاربر و زمان انقضا باشد.

@app.route('/login', methods=['POST'])
def login():
    # دریافت اطلاعات ارسال شده توسط کاربر
    auth = request.json
    
    if not auth or not auth.get('username') or not auth.get('password'):
        return jsonify({'message': 'نام کاربری و رمز عبور الزامی است'}), ۴۰۰

    # در اینجا معمولاً چک کردن دیتابیس انجام می‌شود
    # ما برای سادگی فرض می‌کنیم کاربر admin با رمز ۱۲۳۴۵ است
    if auth['username'] == 'admin' and auth['password'] == '۱۲۳۴۵':
        # تنظیم زمان انقضا (مثلاً ۳۰ دقیقه دیگر)
        expiration_time = datetime.datetime.utcnow() + datetime.timedelta(minutes=۳۰)
        
        # ساخت Payload توکن
        payload = {
            'user': auth['username'],
            'exp': expiration_time  # زمان انقضا (اختیاری اما توصیه شده)
        }
        
        # تولید توکن با استفاده از الگوریتم HS256
        token = jwt.encode(payload, app.config['SECRET_KEY'], algorithm="HS256")
        
        return jsonify({'token': token})
    
    return jsonify({'message': 'نام کاربری یا رمز عبور اشتباه است'}), ۴۰۱

۲. ایجاد تابع محافظ (Decorator) برای احراز هویت

حالا که توکن را داریم، نیاز به راهی داریم تا مسیرهای محافظت شده (Protected Routes) را بسازیم. ما یک تابع دکوراتور می‌نویسیم که قبل از اجرای تابع اصلی مسیر، توکن ارسال شده در هدر درخواست (Header) را چک می‌کند.

def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = None
        
        # توکن معمولاً در هدر Authorization با فرمت Bearer  ارسال می‌شود
        if 'Authorization' in request.headers:
            auth_header = request.headers['Authorization']
            try:
                token = auth_header.split(" ")[۱]  # جدا کردن توکن از کلمه Bearer
            except IndexError:
                return jsonify({'message': 'فرمت توکن نامعتبر است'}), ۴۰۱
        
        if not token:
            return jsonify({'message': 'توکن ارسال نشده است'}), ۴۰۱
        
        try:
            # تلاش برای دیکد کردن توکن و بررسی اعتبار آن
            data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
            current_user = data['user']
        except jwt.ExpiredSignatureError:
            return jsonify({'message': 'توکن منقضی شده است'}), ۴۰۱
        except jwt.InvalidTokenError:
            return jsonify({'message': 'توکن نامعتبر است'}), ۴۰۱
            
        # ارسال کاربر شناسایی شده به تابع اصلی
        return f(current_user, *args, **kwargs)
    
    return decorated

۳. استفاده از مسیر محافظت شده

اکنون می‌توانیم از دکوراتور token_required روی هر مسیری که نیاز به احراز هویت دارد استفاده کنیم. اگر کاربر توکن معتبر نداشته باشد، به محتوای مسیر دسترسی نخواهد داشت.

@app.route('/protected')
@token_required
def protected_route(current_user):
    # این تابع فقط در صورتی اجرا می‌شود که توکن معتبر باشد
    return jsonify({'message': f'سلام {current_user}! شما به یک منطقه محافظت شده دسترسی دارید.'})

۴. تست سیستم با Postman یا cURL

برای تست این سیستم، مراحل زیر را طی کنید:

  1. دریافت توکن: یک درخواست POST به آدرس /login با بدنه JSON زیر ارسال کنید:
    {
      "username": "admin",
      "password": "۱۲۳۴۵"
    }

    پاسخ شامل یک رشته طولانی (توکن) خواهد بود.

  2. دسترسی به مسیر محافظت شده: یک درخواست GET به آدرس /protected ارسال کنید. در بخش Headers، کلید Authorization را اضافه کنید و مقدار آن را برابر با Bearer YOUR_TOKEN_HERE قرار دهید.

نکات امنیتی مهم

  • انتقال امن: همیشه سعی کنید توکن‌ها را از طریق پروتکل HTTPS ارسال کنید تا در برابر حملات شنود (Man-in-the-Middle) محافظت شوند.
  • ذخیره‌سازی: توکن‌ها را در سمت کلاینت (مرورگر) در HttpOnly Cookies ذخیره کنید تا در برابر حملات XSS امن باشند. ذخیره در LocalStorage خطرات امنیتی دارد.
  • مدت زمان انقضا: همیشه برای توکن‌ها زمان انقضا کوتاه (مثلاً ۱۵ دقیقه) تعیین کنید و از مکانیزم “تازه‌سازی توکن” (Refresh Token) برای جلسات طولانی استفاده کنید.

جمع‌بندی

در این بخش، یاد گرفتیم چگونه با استفاده از کتابخانه PyJWT در فلسک، یک سیستم احراز هویت مدرن و بدون وضعیت (Stateless) پیاده‌سازی کنیم. ما توکن را تولید کردیم، آن را اعتبارسنجی نمودیم و مسیرهای حساس را محافظت کردیم. این روش پایه و اساس اکثر APIهای مدرن امروزی است.

دیدگاه خود را اینجا بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

فیلدهای دلخواه برای نمایش را انتخاب کنید. سایر فیلدها مخفی می شود. برای ترتیب دلخواه فیلدها را به محل دلخواه بکشید و رها کنید.
  • عكس
  • شناسه محصول
  • امتیاز
  • قیمت
  • موجودی
  • موجودی
  • افزودن به سبد خرید
  • توضیحات
  • محتوا
  • وزن
  • ابعاد
  • اطلاعات تکمیلی
برای مخفی شدن نوار مقایسه، بیرون از کادر کلیک کنید
مقایسه