Syntax | سینتکس
3.01K subscribers
410 photos
108 videos
35 files
378 links
Download Telegram
JWT

چند روزه پستای تخصصی طور نذاشتم.
امروز قراره نحوه پیاده سازی Jwt Authentication بصورت حرفه ای بررسی کنیم.

اول از همه یه سری مفاهیم و توضیحات درباره jwt رو مرور میکنیم بعدش بصورت عملی پیاده سازی میکنیم.

#JWT

@khat_academy
🔥9👍2
JWT (Json Web Token):

یک استاندارد برای ایجاد توکن‌های دیجیتاله که تو فرایند احراز هویت و تأیید اعتبار در برنامه‌ها و سیستم‌های وب استفاده می‌شه. JWT یک توکن کم حجم و ایمن هستش که اطلاعاتی رو تو خودش ذخیره می کنه و به صورت امضاشده به عنوان یک رشته Base64 ارسال می کنه.

چرا بصورت Base64 ارسال میشه؟

1. قابلیت انتقال توی فرمت متنی:
رشته‌های Base64 متشکل از کاراکترهای الفبای بیتی هستن که می‌تونن بدون مشکل در فرمت‌های متنی ارسال و ذخیره بشن. باعث می‌شه که توکن JWT بدون نیاز به فرمت‌های خاص بتونه تو درخواست‌ها و پاسخ‌های HTTP ارسال بشه.

2. حجم کمتر:
با استفاده از رشته‌های Base64 برای نمایش سربرگ، حجم توکن JWT کمتر می شه. چون رشته‌های Base64 نسبت به داده اصلی کوچیک ترن. این کاهش حجم باعث می‌شه توکن JWT به صورت کم‌حجم‌تری قابل انتقال و ذخیره بشه.

آیا Base64 بودن امنیت توکنو تضمین می کنه؟
استفاده از Base64 هیچ تأثیری تو امنیت توکن نداره. امضای دیجیتال توکن تو قسمت امضا (Signature) صورت می‌گیره و اصالت و صحت سربرگ توسط امضا بررسی می‌شه. بنابراین، حتی اگر سربرگ در قالب Base64 لو بره، امنیت توکن تضمین می‌شه.

#JWT

@khat_academy
👍72
Refresh Token, Access Token

تو مکانیزم JWT، معمولاً از دو بخش توکن استفاده می‌شه که به عنوان "Refresh Token" و "Access Token" شناخته می‌شن. هر کدوم از این دو توکن نقش و وظیفه‌های مختص خودشو تو فرآیند احراز هویت و مدیریت دسترسی‌ها دارن.

1. Refresh Token:
رفرش توکن، توکنی است که به کاربر در زمان احراز هویت و داده میشه. این توکن معمولاً دارای مدت زمان اعتبار بلندتری نسبت به Access Token هستش و معمولاً توسط سرور صادر می‌شه. وظیفه Refresh Token در تجدید و تمدید Access Token هستش. به عبارت دیگه، هنگامی که Access Token منقضی می‌شه، کاربر می‌تونه Refresh Token رو به سرور ارسال کنه تا یدونه Access Token جدید دریافت کنه بدون نیاز به مجدداً وارد کردن اطلاعات احراز هویت.

2. Access Token:
اکسس توکن، توکنی است که بعد از احراز هویت کاربر به او اختصاص داده می‌شه و برای دسترسی به منابع و انجام عملیات مختلف استفاده می‌شه. این توکن معمولاً دارای مدت زمان اعتبار کوتاه‌تری نسبت به رفرش توکن هستش.
اکسس توکن برای هر درخواست از طریق هدر یا پارامترهای درخواست ارسال می‌شه و سرور با بررسی اعتبار و صحتش، دسترسی کاربر به منابع رو تأیید می‌کنه.

دو دلیل برای اینکه چرا دو نوع توکن داریم؟

1. امنیت بیشتر:
استفاده از توکن Access با مدت زمان اعتبار کوتاهتر، مزیت امنیتی داره. در صورتی که توکن Access در دسترس یک اتکر قرار بگیره، مدت زمانی که می‌تونه ازش استفاده کنه محدوده و احتمال سوءاستفاده کم میشه.

2. مدیریت دسترسی بهتر: با استفاده از دو نوع توکن، مدیریت دسترسی‌ها بهتر امکان‌پذیر می‌شه. با تنظیم مدت زمان اعتبار کوتاهتر برای Access Token، کاربران تو فاصله زمانی کوتاهتری بین درخواست‌ها مجدداً احراز هویت میشن و دسترسی خودشونو تایید می کنن. این به سرور اجازه می‌ده تا در مدت زمان کمتری درخواست‌های کاربران رو بررسی کنه و عملکرد سیستم رو بهبود ببخشه.

شاید از خودتون بپرسید خب اگه رفرش توکن دست هکر بیوفته چی؟
اینجاس که بحث پیاده سازی سیستم احراز هویت امن پیش میاد. یعنی ما باید بررسی کنیم ببینیم شخصی که داره درخواست می ده واقعا خودشه یا نه!

#JWT

@khat_academy
👏8👍2😱2
ساختار JWT

از سه بخش تشکیل شده: سربرگ (Header)، بدنه (Payload) و امضا (Signature). سربرگ شامل اطلاعات مربوط به نوع توکن و الگوریتم امضا هستش، بدنه حاوی اطلاعات مفیدی است که برنامه‌ها می‌تونن ازش استفاده کنن.
امضا برای تأیید اعتبار توکن استفاده می‌شه(امضا رو فقط خودمون می دونیم چیه و اعتبار توکن هم بر اساس امضا می سنجیم).

Header.Payload.Signature

همونطور که تو عکس مشخصه. قسمت header نوع توکن مشخص شده با الگوریتم امضا.

قسمت payload اطلاعاتی که نیازه بهش توکن داشته باشه. مثلا تاریخ انقضا و اینکه توکن برای چه شخصی صادر شده. تو این قسمت ما می تونیم اطلاعات بیشتری رو ذخیره کنیم برای مثال:
last_name, username, user_id ...
خلاصه می تونیم اطلاعات مورد نیازمونو قرارش بدیم تا نیاز نباشه هربار از دیتابیس بگیریم. در نهایت میایم encrypt می کنیم تا قابل خوندن نباشه.

قسمت signature:
امضا به عنوان یک سپر امنیتی برای تشخیص تغییرات در داده‌های توکن و تأیید اینکه توکن توسط یک صادر کننده معتبر ایجاد شده، به کار می‌ره.

پ.ن
تو گوگل سرچ کنید کلی توضیح کامل میاد. بریم سراغ پیاده سازیش

#JWT

@khat_academy
👍9
JWT

اگه شما توسعه دهنده فرانت اند هستید. می تونید سیستم احراز هویت JWT رو توی این پروژه ی واقعی که آنلاینش کردم تست کنید(فعلا آفلاینه)

http://188.121.113.3/api/schema/redoc/

همچنین یک سری قابلیت های دیگه هم در ادامه بهش اضافه می کنم.

#JWT

@khat_academy
7
بررسی استاندارد احراز هویت JWT توی پروژه qanda.

لینک گیت هاب:
https://github.com/alireza-fa/question-and-answer

Model
اولین کاری که میکنیم اینه یک مدل به اسم UserLogin مینویسیم.
اینکه چه فیلد هایی رو میخواید قرار بدید انتخاب خودتونه اما فیلد های مورد نیاز ما این موارد هستش:
user_id
refresh token
expired_at
device
ip_address

Token
یکی از کارهای دیگه که کردیم این هستش که یک سری اطلاعات بیشتری رو توی payload توکن هامون قرار دادیم که این فیلد ها هستش:
username
email
first_name
last_name
device_name
ip_address

دلیل اینکه اینکارو انجام دادیم چیه؟
با اضافه کردن این اطلاعات پرکاربرد دیگه نیاز نیست هر بار از سمت دیتابیس بگیریم.

Encrypt / Decrypt
میخوایم اطلاعاتی که توی payload توکن قرار دادیم قابل دیدن نباشه. پس میایم توکن رو encrypt شده سمت کلاینت ارسال می کنیم و هر وقت که نیاز بود سمت بک اند decrypt میکنیم و عملیات اعتبار سنجی و هرچیزی نیاز هستش رو انجام می دیم.

چجوری توکن رو امن تر کردیم؟
تو مدل UserLogin اطلاعات کاربر موقعی که لاگین می کنه ذخیره کردیم. مثل نام دستگاه و آدرس آی پی. همچنین توی توکن هم اضافه کردیم.
کاری که می کنیم اینه چک می کنیم شخصی که میخواد اکسس توکن جدید بگیره ip address و device name همونه یا نه. اگه اون نبود توکن رو نامعتبر می شماریم.

همچنین برای امنیت بیشتر تو هر درخواست اکسس توکن رو هم می تونیم بررسی کنیم که مشخصاتش با شخصی که داره درخواست میده یکی هستش یا نه

برای بررسی بیشتر حتما به ریپازیتوری گیت هاب سر بزنید. برای حمایت ستاره بدید ممنون میشم.

#JWT

@khat_academy
👍13
پروژه Django Jwt Auth

اگه توی پروژه ی جنگوییتون قراره از JWT استفاده کنید، حتما این ریپازیتوری بدردتون میخوره.

نحوه دیکریپت کردن و انکریپت کردن توی پایتون.

قرار دادن claim های مورد نیاز داخل payload توکن

نحوه نوشتن authentication class کاستوم توی drf

و خیلی موارد دیگه مثل لاگین با شماره موبایل و otp کد و ... رو توی این پروژه پیاده کردم.
البته هنوزم جای کار داره و دوست دارم باهم بهترش کنیم.

وقت زیادی روش گذاشتم ممنون میشم ستاره بدید ❤️

لینک:
https://github.com/alireza-fa/django-jwt-auth

#django #jwt

@Syntax_fa
10❤‍🔥1👍1👎1👏1😍1
با توجه به سوالاتتون، یه سری نکات درباره payload بگم

Access token
تو قسمت payload اطلاعاتی که از کاربر تو قسمت پروفایلش نشون میدیم رو قرارش میدیم
رول های کاربر رو توی یک آرایه قرارش میدیم. برای مثال این کاربر فقط رول پیشفرض رو داره پس اگه اندپوینتی پرمیشن ادمین داشته باشه نمیتونه درسترسی داشته باشه.(چک کردن پرمیشن هارو از طریق middleware انجامش میدیم)

Refresh token
تو قسمت payload مقداری که بتونیم به کاربر دسترسی داشته باشیم رو ذخیره می کنیم. برای مثال UserId
بعد با استفاده از Userid سمت دیتابیس درخواست می زنیم و user رو میگیریم. بعدش یه access token جدید میسازیم.(با توجه به شرایط احراز هویت پروژمون ممکنه در کنار access token یه refresh token جدیدم بسازیم)

نکته مهم اینه access token رو مدت زمانشو کم بذارید.
داخل payload رفرش توکن آنچنان نیاز نیست چیزی جز userId و expireTime قرار بدید.
در نهایت اگه رمزنگاری کنید دیگه کسی جز خودتون نمیتونه اطلاعات توکن رو ببینه.

#JWT

@Syntax_fa
👍8
با این روش وقتی داری توی جنگو از JWT استفاده می کنی،‌response time درخواست هارو به شکل قابل توجهی کمترش کن‌ !!!

توی جنگو اکثر افراد از پکیج Django Simple JWT استفاده می کنن.
پکیج Simple Jwt برای ما یک کلاس به اسم JWTAuthentication می دهد تا بتوانیم به عنوان کلاس Authentication در DRF ازش استفاده کنیم.

یکی از نکاتی که باید درمورد JWTAuthentication بدونید، متد get_user هستش.
هر درخواستی که در هدر آن اکسس توکن رو قرار داده باشید، یک درخواست سمت دیتابیس میزند تا با استفاده از فیلد user_id که در claim توکن ست کرده، اطلاعات کاربر رو بگیره.

نکته همینجاست. هر درخواست مساوی با یک hint سمت دیتابیس !

خب میتونیم چیکار کنیم؟
میتونیم توی claim های توکن اطلاعات بیشتری رو قرار بدیم و یوزر خودمون رو با استفاده از claims توکن بدست بیاریم

برای اینکار دیگه توکن هارو خودمون بصورت دستی میسازیم و claim هارو هم به این شکل به توکن اضافه می کنیم(همچنین توکن رو encrypt می کنیم):

from django.contrib.auth import get_user_model
from rest_framework_simplejwt.tokens import RefreshToken

from .encryption import encrypt

User = get_user_model()

def set_token_claims(token: Token, data: Dict) -> Token:
for key, value in data.items():
token[key] = value

return token


def get_token_by_user(user: User, client_info: Dict) -> Dict:
token = RefreshToken.for_user(user=user)

data = {
"fullname": user.fullname,
"national_code": user.national_code,
"phone_number": user.phone_number,
"email": user.email,
"verified_email": user.verified_email,
"last_image_update": user.last_image_update,
"is_active": user.is_active,
"is_admin": user.is_admin,
"father_name": user.father_name,
"height": str(user.height),
"weight": str(user.weight),
"blood_type": user.blood_type,
**client_info
}

if user.avatar_image:
data["avatar_image"] = user.avatar_image.url

token = set_token_claims(token=token, data=data)

return {
"refresh_token": encrypt(data=str(token)),
"access_token": encrypt(data=str(token.access_token)),
}


در نهایت کلاس Authentication خودمون رو پیاده سازیش می کنیم:
from django.utils.translation import gettext_lazy as _
from django.contrib.auth import get_user_model

from rest_framework_simplejwt.authentication import JWTAuthentication, AuthUser
from rest_framework_simplejwt.tokens import Token
from rest_framework_simplejwt.exceptions import InvalidToken

from .encryption import decrypt


User = get_user_model()


class CustomAuthentication(JWTAuthentication):

def get_validated_token(self, raw_token: bytes) -> Token:
try:
token = decrypt(encrypted=raw_token)
except ValueError:
raise InvalidToken(
{
"detail": _("Given token not valid for any token type"),
}
)
return super().get_validated_token(token.encode())

def get_user(self, validated_token: Token) -> AuthUser:
return User(
id=validated_token["user_id"],
fullname=validated_token["fullname"],
national_code=validated_token["national_code"],
phone_number=validated_token["phone_number"],
email=validated_token["email"],
verified_email=validated_token["verified_email"],
avatar_image=validated_token.get("avatar_image"),
last_image_update=validated_token["last_image_update"],
is_active=validated_token["is_active"],
is_admin=validated_token["is_admin"],
father_name=validated_token["father_name"],
height=validated_token["height"],
weight=validated_token["weight"],
blood_type=validated_token["blood_type"]
)


حالا شما با این روش، از قابلیت های jwt توی جنگو به شکل بهتری می تونید استفاده کنید.

(صرفا جهت آشنایی گفتم. چون توی جنگو که همه چی از قبل نوشته شده خیلی وقتا فراموش میشه یک ابزار در پشت صحنه به چه صورت کار میکنه)

#Django #JWT

@Syntax_fa
👍91
معرفی پکیج d_jwt_auth

پکیج d_jwt_auth برای کار با jwt در جنگو هستش.

چه قابلیت هایی داره؟
۱.سادگی. تمامی کارهارو تنها با 4 فانکشن میتونید انجام بدید.
۲. حداقل دوبرابر simple_jwt پرفورمنس بهتری داره!
۳. امنیت بیشتر بواسطه رمزنگاری کردن توکن
۴. چک کردن آی پی و دستگاهی که توکن برای اون صادر شده با آی پی آدرس و دیوایسی که ریکوئست زده.
۵. نحوه نامعتبر کردن توکن به شیوه خیلی کارآمد تر
و ...

مثال از نحوه استفاده:

اول از همه نصبش می کنیم:
pip install d_jwt_auth

تو لیست اپ ها اضافش می کنم:
INSTALLED_APPS = [
    ...
    "d_jwt_auth",
]

بعدش migrate بزنید.

کلاس Authentication رو قرار میدیم:
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'd_jwt_auth.authenticate.JWTAuthentication',
        ...
    ),
}

نحوه ساخت توکن:
from d_jwt_auth.token import generate_token 

class LoginView(APIView):
    def post(self, request):
        ...
        token = generate_token(request=request, user=user)
        return Response(data=token, status=status.HTTP_200_OK)

Github:
https://github.com/alireza-fa/django-jwt-auth

Pypi:
https://pypi.org/project/d-jwt-auth/

(برای حمایت ستاره فراموش نشه)

قبل استفاده حتما داکیومنت رو کامل بخونید

#django #jwt

@Syntax_fa
🔥8👍4
بررسی نحوه کارکرد توکن jwt

یک توکن JWT از سه بخش تشکیل شده است:

Header:
در هدر، الگوریتم مورد استفاده برای امضا مشخص می‌شود. این می‌تواند الگوریتم‌های مختلفی باشد که در ادامه توضیح داده خواهد شد.

Payload:
در این بخش، اطلاعات مورد نیاز قرار می‌گیرد. به‌صورت پایه‌ای، user_id کاربری که توکن برای او صادر شده و فیلد exp برای تاریخ انقضای توکن (به صورت timestamp) ضروری است.

Signature:
این بخش برای صحت‌سنجی توکن استفاده می‌شود که در ادامه روش آن توضیح داده خواهد شد.

بنابراین، توکن ما سه بخش دارد. قسمت‌های header و payload به‌صورت یک آبجکت با کلید و مقدار هستند. به‌عنوان مثال، هدر به این صورت است:
{"alg": "HS256"}

و قسمت payload به این صورت:
{"user_id": 1, "exp": 111222558}


برای بازگرداندن یک رشته یکپارچه به کلاینت، این سه بخش را به روش زیر ترکیب می‌کنیم:

1. Base64Url Encoding:
قسمت‌های header و payload را به Base64Url تبدیل می‌کنیم. Base64Url رشته‌ای برمی‌گرداند که شامل کاراکترهای ASCII اصلی است.

2. ترکیب بخش‌ها:

پس از تبدیل به Base64Url، بخش‌های header و payload را با . به یکدیگر متصل می‌کنیم:

   header.payload

3. ساخت Signature:
بر اساس header.payload و با استفاده از الگوریتم مشخص‌شده و یک کلید محرمانه در سرور، امضا ساخته می‌شود. سپس امضا را با . به رشته اضافه می‌کنیم:
   header.payload.signature


استفاده از
JWT:
کلاینت توکن را در هر درخواست احراز هویت ارسال می‌کند (معمولاً در هدر درخواست).
توکن با «نقطه» به سه بخش جدا می‌شود:

1. دیکود کردن Header:

هدر را از Base64Url دیکود کرده و الگوریتم آن را بررسی می‌کنیم.

2. اعتبارسنجی Signature:

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

3. بررسی Payload:

پیلود را دیکود کرده و فیلد exp را با زمان فعلی مقایسه می‌کنیم. اگر زمان انقضا گذشته باشد، توکن نامعتبر است. در غیر این صورت توکن معتبر است و می‌توان از user_id برای دسترسی به اطلاعات کاربر استفاده کنیم.

تفاوت بین Access Token و Refresh Token:

هر دو ساختار مشابهی دارند. در برخی پروژه‌ها، در payload فیلدی به نام type اضافه می‌کنیم که مشخص می‌کند توکن access است یا refresh. از access token برای احراز هویت کاربر و از refresh token برای دریافت یک access token جدید استفاده می‌شود.

یکی از دلایل استفاده از دو نوع توکن که استفاده کردم:
- Access Token:

ممکن است شامل اطلاعات بیشتری مانند نقش‌ها و پروفایل کاربر باشد. اگر نقش کاربر تغییر کند (مثلاً دیگر ادمین نباشد)، می‌توان access tokens او را نامعتبر کرد و با استفاده از refresh token یک access token جدید صادر کرد که نقش ادمین ندارد.

- Refresh Token:

معمولاً فقط شامل user_id و exp است و برای امنیت بیشتر می‌توان ip_address و device_name را نیز اضافه کرد. این اطلاعات برای ایجاد یک access token جدید استفاده می‌شود.

#jwt

@Syntax_fa
👍20👌3💋3