چند سالی است که پایتون به یکی از محبوبترین زبانهای برنامه نویسی تبدیل شده است. از طرفی، پایتون یکی از قابل فهمترین و دوستداشتنیترین زبانهای برنامهنویسی دنیا محسوب میشود و یکی از گزینههای مناسب برای شروع برنامهنویسی است. فریمورک قدرتمند وب پایتون، جنگو (Django) به ما این امکان را میدهد تا به توسعه وباپلیکیشنها که همان نرمافزارهای مبتنی بر وب هستند، بپردازیم. وب اپلیکیشن یک برنامه کامپیوتری است که از تکنولوژی وب و توانایی مرورگرها برای انجام وظایف استفاده میکند. اغلب وبسایتهایی که ما به طور روزانه از آنها استفاده میکنیم حداقل یک وباپلیکیشن دارند. در این مقاله قصد داریم به مفهوم احراز هویت (Authentication) که یکی از کاربردیترین و مهمترین بخشهای هر برنامهای محسوب میشود، بپردازیم.
قبل از هر چیز، بهتر است با مفهوم احراز هویت آشنا شویم، احراز هویت به چه معناست؟
در علوم کامپیوتر، این اصطلاح معمولاً با اثبات هویت کاربر مرتبط میشود. معمولاً یک کاربر هویت خود را با ارائه اعتبار خود، یعنی اطلاعات توافق شدهای که بین کاربر و سیستم (سرور) به اشتراک گذاشته میشود، اثبات میکند و انواع مختلفی دارد. این اطلاعات شامل مواردی مانند نام کاربری، آدرس ایمیل، رمز عبور و شماره تماس خواهد بود. بخش احراز هویت در تمام شبکههای اجتماعی و بیشتر پلتفرمهایی که ما روزانه از آن استفاده میکنیم، استفاده میشود. به طور مثال، ما به عنوان یک کاربر با نام کاربری، رمز عبور یا آدرس ایمیل مشخص که به عنوان بخشی از هویت خودمان تأیید کردیم، میتوانیم وارد یک سایت شویم تا از خدمات برنامه استفاده کنیم.
در انتهای این آموزش قصد توسعه برنامهای با امکانات احراز هویت مانند ثبت نام کاربران (Register)، ورود کاربر(Log in) و تغییر رمز عبور (Change passwords) را خواهیم داشت.
این مقاله از آخرین نسخه پایتون و جنگو پشتیبانی میکند، در این مقاله تلاش میکنیم به سادهترین شکل ممکن مدیریت و ایجاد حسابهای کاربری را در قالب احراز هویت آموزش دهیم. حتماً در نظر داشته باشید که بهتر است از محیط مجازی (Virtual Environments) برای این پروژه استفاده کنیم. سوالی که ممکن است برای شما پیش بیاید این است که محیط مجازی به چه معناست؟ به عبارت سادهتر، پکیجهای پایتون همگی در یک مسیر مشخص نصب میشوند، حال در نظر بگیریم که در پروژههای متفاوت نیاز به نسخههای مختلف که شامل کتابخانههای متفاوت است، داریم. در این شرایط، ایجاد محیطهای مجازی راهحل مورد نظر ما است که به ما این امکان را میدهد تا همزمان از نسخههای مختلف جنگو استفاده کنیم.
با استفاده از کدهایی که در زیر آمده است، شما میتوانید محیط مجازی که برای لینوکس، ویندوز و macOS کاربردهای فراوانی دارد، ایجاد کنید، اما سوالی که در اینجا حائز اهمیت است، این است که این کدها را در چه قسمتی باید استفاده کرد؟
برای مدیریت و ایجاد پروژه جنگو از (Command prompt) که کاربران ویندوزی آن را به اسم cmd میشناسند میتوانید استفاده کنید. با توجه به سیستم عامل مورد استفاده شما میتوانید از کدهای زیر استفاده کنید.
Shell:
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ python -m pip install –upgrade pip
(venv) $ python -m pip install Django
اگر کاربر ویندوزی هستید، محیط مجازی ایجاد شده با دستور زیر برای شما فعال میشود.
C:\> venv\Scripts\activate
حال، یک پروژه و برنامه جدید ایجاد میکنیم.
Shell:
(venv) $ django-admin startproject authentication(venv) $ cd authentication(venv) $ python manage.py startapp users
اسم پروژه و برنامه ایجاد شده کاملاً اختیاری است و محدودیتی ندارد. ما اینجا به ترتیب از دو عنوان authentication و users استفاده میکنیم.
حال، در این قسمت وارد بخش setting.py در پروژه شده و تنظیمات مربوط به اپلیکیشن خود که در اینجا با نام (users) ایجاد کردیم را اضافه میکنیم.
# authentication/settings.pyINSTALLED_APPS = [“users”,”django.contrib.admin”,”django.contrib.auth”,”django.contrib.contenttypes”,”django.contrib.sessions”,”django.contrib.messages”,”django.contrib.staticfiles”,]
قدم بعدی استفاده از دستور مایگریشن (migration) برای ایجاد یا انتقال آخرین تغییرات در دیتابیس است.
- کلمه migration در لغت به مهاجرت اشاره دارد اما در علم کامپیوتر و برنامه نویسی مفهوم انتقال دیتا را برای کاربران دارد. هدف ما از مایگریشن انتقال از یک یا چند دیتابیس به دیتابیسهای هدف است.
در ادامه داریم.
(venv) $ python manage.py migrate
برای برقراری ارتباط با سرور و اجرای اپلیکیشن، از کد زیر میتوانید استفاده کنید.
(venv) $ python manage.py runserver
ما در این آموزش از تنظیماتuser management که به صورت پیشفرض در جنگو، ایجاد شده است، استفاده میکنیم اما با درک بهتر و دقیقتر از این پروژه شما میتوانید مدلهای خود را سفارشیسازی (Customize) کنید.
از طرفی، نیازمند شناسایی مدیریت کاربران، ادمین نیز هستیم، پس در این مرحله باید دسترسی مربوط به پنل admin را ایجاد کنیم. پنل ادمین یا مدیریت یکی از کاملترین و قدرتمندترین بخشهای فریموورک جنگو محسوب میشود که امکانات کاربردی زیادی برای توسعهدهندگان دارد.
- اگر علاقمند به مطالعه بیشتر این بخش و امکانات آن را دارید، بهترین منبع خود سایت جنگو است که شما میتوانید از لینک زیر این بخش را مطالعه کنید.
✔ https://docs.djangoproject.com/en/4.1/intro/tutorial02
قبل از اینکه ادمین را ایجاد کنیم، بهتر است برای راحتی کار خود، تغییراتی در تنظیمات پیشفرض جنگو ایجاد کنیم. جنگو به طور پیشفرض رمزعبورهای قوی را اعمال میکند. ما در طول این پروژه نیاز به رمز عبورهای ساده داریم که بتوانیم به راحتی آن را تغییر بدهیم، پس به آدرس setting.py رفته و بخش زیر را کامنت میکنیم. کامنت کردن در برنامهنویسی به چه معناست؟
- کامنت کردن کدها یا کامنتگذاری در برنامهنویسی برای اضافه کردن توضیحات در مورد بخش خاصی از کدها کاربرد فراوانی دارد. در واقع بخش کامنت شده که در پایتون با نماد (#) نمایش داده میشود، در طول پروژه اجرا نخواهد شد. مزیت اینکار نسبت به پاککردن کدها این است که گاهی دوباره بخشی از تنظیمات و کدهای پاک شده ممکن است در مراحل بعدی توسعه نرمافزار استفاده شود، پس بهتر است که از کامنت کردن به جای پاک کردن کدهای مهم استفاده کنیم. (Ctrl + /)
# authentication/settings.py
AUTH_PASSWORD_VALIDATORS = [
# {
# “NAME”: “django.contrib.auth.password_validation.UserAttributeSimilarityValidator”,
# },
# {
# “NAME”: “django.contrib.auth.password_validation.MinimumLengthValidator”,
# },
# {
# “NAME”: “django.contrib.auth.password_validation.CommonPasswordValidator”,
# },
# {
# “NAME”: “django.contrib.auth.password_validation.NumericPasswordValidator”,
# },
]
حال ادمین که با اسم (Superuser) شناخته میشود را ایجاد میکنیم.
Shell:
(venv) $ python manage.py createsuperuser
Username (leave blank to use ‘pawel’): admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.
در مرحله بعدی بهتر است شما یک درک اولیه از تمپلیتها (Templates) داشته باشید. قالبهای (HTML) نحوه نمایش را برای کاربران پیادهسازی میکند، پس برای نمایش دادهها نیاز به قالبهای مختلف داریم اما بهتر است این قالبها ساختار منظم و خوانایی داشته باشند. مسیر قالبها به طور پیشفرض وجود ندارند و ما باید به صورت دستی این مسیرها را به پروژه اضافه کنیم. پس در اپلیکیشن users که قبلتر به تعریف آن پرداخته شده است، پوشه (templates) را ایجاد میکنیم. در این بخش یک قالب اصلی برای کلیه قالبها به اسم base.html ایجاد میکنیم که بقیه قالبهای پروژه از آن ارثبری میکنند. در بخش بعدی، نیازمند ایجاد دو پوشه جدید به اسمهای (registration) و (users) داریم که هر کدام شامل چند قالب متفاوت خواهد بود. انتظار میرود پروژه و برنامه ما در این مرحله، ساختاری مشابه نمودار زیر را داشته باشد.
authentication/
│
├── awesome_website/
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
│
├── users/
│ │
│ ├── migrations/
│ │ └── __init__.py
│ │
│ ├── templates/
│ │ │
│ │ ├── registration/ ← Templates used by Django user management
│ │ │
│ │ ├── users/ ← Other templates of your application
│ │ │
│ │ └── base.html ← The base template of your application
│ │
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
│
├── db.sqlite3
└── manage.py
قالب base.html ساختاری مشابه ساختار زیر خواهد داشت.
<!–users/templates/base.html–>
<h1>Welcome to Authentication Project</h1>
{% block content %}
{% endblock %}
هدف ما از ایجاد قالب base.html درست کردن یک ساختار کلی برای تمامی قالبهاست. به طور مثال ما نیاز داریم تمامی صفحات برنامه با یک تصویر پسزمینه با رنگهای مشخص و المانهای ثابت نمایش داده شود، لذا کدها و تنظیمات مربوط در این قالب اضافه خواهد شد و نیازی به تکرار دوباره کدها در هر صفحه (HTML) نیست. دستهبندی تمپلیتها با توجه به سلیقه خود توسعهدهنده میتواند ساختار متفاوتی داشته باشد.
قالبهای اصلی مربوط به کاربران مثل ورود یا لاگین، تغییر رمز در قسمت (Registration) قرار میگیرد. باقی صفحات مانند ثبتنام کاربران جدید و صفحه پیشخوان (Dashboard) در بخش (users) قرار میگیرد.
<!–users/templates/users/dashboard.html–>
{% extends ‘base.html’ %}
{% block content %}
Hello, {{ user.username|default:’Guest’ }}!
{% endblock %}
تا اینجا اپلیکیشن ما هنوز تکمیل نشده است و برای کاربران شناخته شده است و به صورت ناشناس در قسمت پیشخوان، پیام سلام را نشان میدهد.
برای ایجاد ارتباط بین صفحات و یا به بیانی دیگر خواندن (HTML) باید به بخش (views.py) رفته و با کمک رندر کردن فایلها را به کاربران نمایش بدهیم.
حال سوالی که در این قسمت پیش میاد، این است که رند در برنامهنویسی به چه معناست؟ رندر در واقع تابعی از کتابخانههای جنگو در بخش توسعه وب است که بین اپلیکیشن ما و کدهای HTML، CSS ارتباط ایجاد میکند و محتوایی که قصد داریم کاربر مشاهده کند را نمایش میدهد.
# users/urls.py
from django.shortcuts import render
def dashboard(request):
return render(request, “users/dashboard.html”)
ما نیازمند این هستیم که آدرسهای URL، اپلیکیشن را تعریف کنیم. پس آدرس users/urls.py را اضافه میکنیم.
# users/urls.py
from django.urls import include, path
from .import views
urlpatterns = [
path(‘dashboard/’, views.dashboard, name=’dashboard’)
]
هدف ما ایجاد ارتباط بین URL اپلیکیشن (users) و پروژه اصلی (authentication) خواهد بود.
# authentication/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(”, include(‘users.urls’)),
]
در این قسمت لازم است پیشخوان (dashboard) را تست کنیم.
در ادامه، آدرس http://localhost:8000/dashboard/ را باز میکنیم، صفحه ذیل را در ادامه مشاهده میکنید.
حالا به پنل ادمین به آدرسhttp://localhost:8000/admin/ رفته و با نام کاربری ادمین که قبلتر آن را معرفی کردیم، وارد داشبورد شده اما این سری، تغییرات زیر را مشاهده میکنید.
با بررسی مجدد کدها متوجه میشوید که تمپلیتها به درستی کار میکنند اما اپلیکیشن ما به چیزی فراتر از یک داشبورد ساده نیاز دارد.
from django.urls import include, path
from .import views
urlpatterns = [
path(‘dashboard/’, views.dashboard, name=’dashboard’),
path(‘accounts/’, include(“django.contrib.auth.urls”)),
]
با اضافه کردن کد بالا دسترسی به مسیرهای زیر برای شما ممکن خواهد شد. در واقع این بخشها از قبل در کتابخانه پایتون ایجاد شده است.
accounts/login/
accounts/logout/
accounts/password_change/
accounts/password_change/done/
accounts/password_reset/
accounts/password_reset/done/
accounts/reset/<uidb64>/<token>/
accounts/reset/done/
🔵 ایجاد صفحهLogin :
برای ایجاد صفحه Login کافی است در مسیر users/templates/registration/login.html فایل HTML زیر را ایجاد کنیم.
{% extends ‘base.html’ %}
{% block content %}
<h2>Login</h2>
<form method=”post”>
{% csrf_token %}
{{ form.as_p }}
<input type=”submit” value=”Login”>
</form>
<a href=”{% url ‘dashboard’ %}”>Back to dashboard</a>
{% endblock %}
برای درک بهتر کدهای فوق، بهتر است مطالعهای بر روی فرمهایHTML داشته باشید. کدهای بالا یک فرم ساده برای ورود کاربران خواهد بود. همچنین با لینک زیر، شما میتوانید درک بهتری از این موضوع داشته باشید.
⭕ https://www.w3schools.com/html/
در کدهای بالا استفاده از csrf_token شاید برای شما عجیب باشد اما باید بدانید که جنگو دارای یک تگ خاص به اسم CSRF است که برای بالا بردن امنیت و جلوگیری از حملات مخرب کاربرد فراوانی دارد و باید از آن استفاده کنیم. کدهایی هم که داخل {% %} قرار میگیرد در واقع به زبان پایتون نوشته شده است و این قابلیت جنگو محسوب میشود.
با استفاده از کدهای زیر شما میتوانید ظاهر صفحه HTML خود را ارتقا دهید که در نتیجه ظاهر تمامی صفحاتی که از این صفحه ارثبری میکنند، هم تغییر میکند. زبان CSS یکی از بهترین ابزارها برای بهبود ظاهر سایت شما است، پس اگر آشنایی اولیهای با این زبان داشته باشید، کمک شایانی به یادگیری شما خواهد کرد.
⭕ https://www.w3schools.com/css/
حال اگر به آدرس http://localhost:8000/accounts/login/ بروید، میتوانید تغییرات اعمال شده را مشاهده کنید.
در این بخش با اطلاعات ادمین که قبلاً وارد کردهاید، میتوانید وارد شده و صفحه زیر را مشاهده کنید.
خطا یا (Error) که بعد از لاگین به ما نشان داده میشود، به این معناست که مسیر accounts/profile/ تعریف نشده است. جنگو این امکان را به ما میدهد که به جای ایجاد یک view جدید، بتوانیم به بخش setting.py رفته و آدرس پیشفرض را به آدرسی که نیاز داریم، تغییر بدهیم. در این قسمت ما داشبورد را انتخاب میکنیم.
# authentication/settings.py
LOGIN_REDIRECT_URL = “dashboard”
حال میتوانیم مجدداً وارد صفحه شویم و به صفحه داشبورد برویم.
🔵 ایجاد کردن صفحه Logout:
بعد از ورود به سایت، کاربرها نیاز به خروج دارند، اما در این قسمت کار بسیار ساده است و نیازی به فرم جداگانه نداریم، تنها کافی است با یک آدرسدهی ساده این بخش را اضافه کنیم. اینجا به درک درستی از LOGOUT_REDIRECT_URL که بالاتر تغییر دادیم، خواهیم رسید. به آدرس زیر دقت کنید:
registration/logged_out.html
این همان مسیری است که در کتابخانه جنگو به صورت پیشفرض از قبل ایجاد شده است.
{% extends ‘base.html’ %}
{% block content %}
Hello, {{ user.username|default:’Guest’ }}!
<div>
{% if user.is_authenticated %}
<a href=”{% url ‘logout’ %}”>Logout</a>
{% else %}
<a href=”{% url ‘login’ %}”>Login</a>
{% endif %}
</div>
{% endblock %}
زمانی که وارد اپلیکیشن میشویم و به اصطلاح لاگین میکنیم، در واقع گزاره user.is_authenticated به شکل تابع True خواهد بود. در این حالت جنگو گزینه مربوط به خروج را به ما نمایش میدهد. اگر این مقدار به شکل تابع False تغییر کند، کاربر به عنوان ناشناس یا AnonymousUser نمایش داده میشود و در عوض گزینه ورود را به کاربر نشون میدهد.
🔵 ایجاد کردن صفحه تغییر رمز:
یکی از ویژگیهای هر اپلیکیشن بعد از ورود و خروج کاربران، قابلیت تغییر رمز عبور (password) برای کاربر است. پس در ادامه آن را پیادهسازی میکنیم. کاربرها در این مرحله میتوانند با ارسال درخواست تغییر رمز عبور به ادمین اصلی این کار را انجام بدهند اما این کار منطقی است؟
همانطور که حدس زدید، بهترین راهحل ایجاد قابلیت تغییر رمز با کمک فرمها خواهد بود. ما دو صفحه HTML جدید نیاز داریم:
فرم اول:
users/templates/registration/password_change_form.html
{% extends ‘base.html’ %}
{% block content %}
<h2>Change password</h2>
<form method=”post”>
{% csrf_token %}
{{ form.as_p }}
<input type=”submit” value=”Change”>
</form>
<a href=”{% url ‘dashboard’ %}”>Back to dashboard</a>
{% endblock %}
این تمپلیت کاملاً مشابه صفحه Login که قبلاً تعریف کردیم، است با این تفاوت که خود جنگو این بار فرم متفاوتی را به کاربر نشان میدهد.
حال به سراغ تمپلیت بعدی خواهیم رفت. در این صفحه تنها به کاربر اعلام میکنیم که رمز عبور با موفقیت تغییر کرده است.
users/templates/registration/password_change_done.html
{% extends ‘base.html’ %}
{% block content %}
<h2>Password changed</h2>
<a href=”{% url ‘dashboard’ %}”>Back to dashboard</a>
{% endblock %}
حال باید این قابلیت جدید برنامه را به صفحه داشبورد هم اضافه کنیم، پس خواهیم داشت.
{% extends ‘base.html’ %}
{% block content %}
Hello, {{ user.username|default:’Guest’ }}!
<div>
{% if user.is_authenticated %}
<a href=”{% url ‘logout’ %}”>Logout</a>
<a href=”{% url ‘password_change’ %}”>Change password</a>
{% else %}
<a href=”{% url ‘login’ %}”>Login</a>
{% endif %}
</div>
{% endblock %}
حال میتوانیم اپلیکیشن احراز هویت را از آدرس زیر هم تست کنیم.
http://localhost:8000/accounts/password_change/
جالب است بدانید، جنگو آنقدر باهوش است که بعد از کلیک بر روی لینک بالا، میتواند تشخیص بدهد شما در ابتدا لازم است وارد سایت شوید.
حال به راحتی میتوانید وارد برنامه شوید، رمز عبور را تغییر دهید و خروج کنید، اما اگر کاربر جدیدی قصد دارد ثبتنام کند، باید چه کاری انجام بدهد؟
🔵 ایجاد کردن صفحه ثبتنام (Signup):
جنگو برخلاف سریهای قبل گزینه پیشفرضی برای ایجاد کاربر جدید ندارد، پس خودمان دست بکار خواهیم شد، لازم است بدانید جنگو فرمهای کاربردی زیادی برای ما ایجاد کرده است.
➡https://docs.djangoproject.com/en/4.1/topics/auth/default/#django.contrib.auth.forms.UserCreationForm
در اینجا میتوانیم از UserCreationForm استفاده کنیم چون تمامی بخشهای اصلی برای عملیات احراز هویت به جز آدرس ایمیل را دارد ولی باز هم جای نگرانی ندارد چون میتوانیم این بخش را هم به فرم اضافه کنیم.
users/forms.py
from django.contrib.auth.forms import UserCreationForm
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
fields = UserCreationForm.Meta.fields + (“email”,)
شاید برای شما این سوال پیش آمده باشد که class meta به چه معناست؟
کلاس متا برای تغییر رفتارهای مدل مثل ویرایش یا شخصیسازی کاربرد فراوانی دارد، در این بخش ما قصد اضافه کردن آدرس ایمیل را داریم، پس لازم است از این گزینه استفاده کنیم.
مرحله بعدی اضافه کردن تابع ثبتنام (register) در بخش views.py هست. پس خواهیم داشت.
users/views.py
from django.contrib.auth import login
from django.shortcuts import redirect, render
from django.urls import reverse
from users.forms import CustomUserCreationForm
def dashboard(request):
return render(request, “users/dashboard.html”)
def register(request):
if request.method == “GET”:
return render(
request, “users/register.html”,
{“form”: CustomUserCreationForm}
)
elif request.method == “POST”:
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect(reverse(“dashboard”))
حتماً برای شما سوال شده است که چرا بار اول از روش GET استفاده کردیم اما دفعه بعد از روش POST؟
اگر قرار باشد بخش views نمایش داده شود، از روش GET استفاده میکنیم. بعد از اینکه فرم ارسال شد تنها با متد POST قابل دسترسی خواهد بود. برای ما مهم است که درک مناسبی از روشهای GET و POST داشته باشیم. لینک های زیر میتواند تا حدودی در این زمینه به شما کمک کند.
➡https://www.w3schools.com/tags/ref_httpmethods.asp
➡https://www.guru99.com/difference-get-post-http.html
حال وقتش است که تمپلیت رجیستری یا ثبتنام را پیادهسازی کنیم.
users/templates/users/register.html
{% extends ‘base.html’ %}
{% block content %}
<h2>Register</h2>
<form method=”post”>
{% csrf_token %}
{{form}}
<input type=”submit” value=”Register”>
</form>
<a href=”{% url ‘login’ %}”>Back to login</a>
{% endblock %}
حتماً به یاد داشته باشید چون تابع جدید (register) را اضافه کردیم، پس باید URL مربوط به خودش را هم در بخش users/urls.py اضافه کنیم. پس خواهیم داشت.
from django.urls import include, path
from .import views
urlpatterns = [
path(‘dashboard/’, views.dashboard, name=’dashboard’),
path(‘accounts/’, include(“django.contrib.auth.urls”)),
path(‘register/’, views.register, name=’register’),
]
حالا به نظر شما فرم ثبتنام را در کجا قرار بدهیم؟
همانطور که حدس زدید بهترین گزینه، در واقع همان صفحه ورود (Log in) خواهد بود. پس در ادامه برای ایجاد تغییر خواهیم داشت:
{% extends ‘base.html’ %}
{% block content %}
<h2>Login</h2>
<form method=”post”>
{% csrf_token %}
{{ form.as_p }}
<input type=”submit” value=”Login”>
</form>
<a href=”{% url ‘dashboard’ %}”>Back to dashboard</a>
<a href=”{% url ‘password_reset’ %}”>Reset password</a>
<a href=”{% url ‘register’ %}”>Register</a>
{% endblock %}
به همین سادگی، ما توانستیم یک اپلیکیشن احراز هویت ساده با امکانات پیشفرض خود جنگو داشته باشیم. این وب اپ میتواند با اضافه شدن به پروژه اصلی بخش احراز هویت کاربران را پوشش بدهد.
Source: https://realpython.com/django-user-management/