احراز هویت در جنگو با استفاده از دکوراتورهای پایتون
ﺯﻣﺎﻥ ﻣﻄﺎﻟﻌﻪ: 11 دقیقه

احراز هویت در جنگو با استفاده از دکوراتورهای پایتون

در این مقاله قصد داریم در ارتباط با دکوراتورها در زبان پایتون صحبت کنیم و شیوه احراز هویت کاربران در جنگو را با استفاده از این توانمندی در زبان پایتون بررسی خواهیم کرد. برای درک این موضوع نیاز است که شما در ابتدا به خوبی با زبان برنامه‌نویسی پایتون آشنایی داشته و همچنین با فریمورک توسعه وب جنگو کار کرده باشید. برای این دو مورد می‌توانید از آموزش‌های برنامه‌نویسی پایتون و Django در وبسایت راکت استفاده کنید.

تمام کدهایی که در این مقاله استفاده شده با نسخه ۳.۸ پایتون و ۳.۲ فریمورک جنگو تست شده و به خوبی کار می‌کند. بنابراین اگر با مشکلی برخورد کردید نسخه‌های پایتون و جنگو را بروزرسانی کنید.

دکوراتور یا Decorator در زبان برنامه‌نویسی پایتون چه کاری را انجام می‌دهد؟

دکوراتور به یک تابع یا کلاس اشاره دارد که یک تابع دیگر را مورد هدف قرار داده و به آن ویژگی‌های جدیدی را اضافه می‌کند. در ادامه می‌توانید چند مثال کلی از این دستور را مشاهده کنید تا بهتر بتوانید این امر را درک کنید.

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

def decorator_function(func):
  print("adding extra functionality")
  return func()

def decorated_function():
  print("decorated function")

decorated_function = decorator_function(decorated_function)

#OUTPUT
# adding extra functionality
# decorated function

در مثال بالا ما تابع decorated_function را به عنوان ورودی تابع دیگری به نام decorator_function قرار داده‌ایم. حال قبل از آنکه خروجی اصلی تعیین شود ما یکسری ویژگی‌های اضافی را به تابع اصلی اضافه کرده و در نهایت تابعی که به عنوان آرگومان در نظر گرفتیم را به خروجی ارسال کردیم. این دقیقا مفهوم دکوراتورها در پایتون است.

اما پایتون یک میانبر راحت‌تر برای این مسئله در نظر گرفته و ما را از انجام چنین کاری باز می‌دارد چرا که نامرتبی کدها را بسیار زیاد می‌کند. حال بیایید با روش جدید یا همان دکوراتورها برای مثال بالا آشنا شویم.

def decorator_function(func):
  print("adding extra functionality")
  return func()


@decorator_function
def decorated_function():
  print("decorated function")

#OUTPUT
# adding extra functionality
# decorated function

همانطور که مشاهده می‌کنید در اینجا بجای آنکه در فرایند بازخوانی توابع را به صورت پیچیده و نامرتب فراخوانی کنیم تابعی که قصد ایجاد تغییراتی در تابع ورودی را دارد با استفاده از علامت @ قبل از تعریف تابع ورودی فراخوانی شده است. به این موضوع در دنیای پایتون دکوراتور گفته می‌شود.

مزایای استفاده از دکوراتور در پایتون

  1. دکوراتورها به ما کمک می‌کنند تا کارایی یک تابع را بدون ایجاد تغییر در کدهای داخلی آن تابع دستکاری کنیم.
  2. می‌توانیم بدون هیچگونه محدودیتی از تعداد دکوراتورهای متعددی برای یک تابع استفاده کنیم.

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

ایجاد سیستم احراز هویت در فریمورک جنگو

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

اما قبل از هرچیزی بیایید یک پروژه جنگویی را ایجاد کنیم.

ایجاد پروژه جنگویی

  1. نصب جنگو
  2. ایجاد یک پروژه جدید
  3. ایجاد یک اپلیکیشن جدید در داخل پروژه
  4. انجام عملیات Migrate
  5. ایجاد فایل url.py در داخل اپلیکیشن
  6. ایجاد فایل forms.py در داخل اپلیکیشن

برای انجام این شش مرحله می‌توانید از کدهای زیر استفاده کنید:

$ python -m pip install django==3.2
$ django-admin startproject authDecorator
$ cd authDecorator
$ python manage.py startapp authApp
$ python manage.py migrate
$ cd authApp
$ type nul > urls.py
$ type nul > forms.py

بعد از انجام این کارها شما یک پروژه authDecorator و یک اپلیکیشن authApp دارید. حال نیاز است که به جنگو در رابطه با اپلیکیشنی که ایجاد کرده‌اید و محل قرارگیری فایل url.py اطلاعاتی را ارائه دهید. برای انجام اینکار وارد فایل authDecorator/settings.py شده و در لیست مربوط به INSTALLED_APPS نام اپلیکیشن‌ خودتان را اضافه کنید.

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "authApp",
]

بعد از انجام این کار وارد فایل urls.py در همان دایرکتوری شده و لیست urlpatterns را تغییر دهید. کاری که نیاز است انجام دهید افزودن آدرس فایل urls مربوط به اپلیکیشن‌تان است.

from django.contrib import admin
from django.urls import path, include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('authApp.urls'))
]

حال که این کارها را انجام دادید آمادگی کامل برای ایجاد سیستم احراز هویت را خواهیم داشت. ابتدای کار نیاز است که فرم ورود را ایجاد کرده و سپس منطق احراز هویت را اضافه می‌کنیم.

ایجاد registration view

در مرحله اول از ایجاد اپلیکیشن‌مان قصد داریم که یک ویو ساده برای کاربران در جهت ایجاد User Registration یا ثبت نام کاربران ایجاد کنیم. برای این کار تنها به یک فرم ساده با ورودی‌های نام کاربری و پسورد قناعت کرده و بعدا براساس این فرم، فرم ورود را نیز ایجاد خواهیم کرد.

برای انجام این کار ما از UserCreationForm که توسط خود جنگو ایجاد شده است استفاده خواهیم کرد. به صورت پیشفرض این فرم حاوی سه ورودی username، password1 و password2 است. برای اینکه از این ویژگی جنگو استفاده کنیم ابتدا نیاز است تا آن را به ویو خود اضافه کنیم:

from django.contrib.auth.forms import UserCreationForm

بعد از این کار کدهای زیر را به ویو مربوط به اپلیکیشن authApp اضافه کنید:

from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect

def register_view(request):
    if request.method == 'POST':
        register_form = UserCreationForm(request.POST)
        if register_form.is_valid():
            register_form.save()
            return redirect('login')
    else:
        register_form = UserCreationForm()
    return render(request, 'register.html', {'register_form': register_form})

در قطعه کد بالا می‌توانید ببینید که تمام کارها از طریق تابع register_view انجام می‌شود. این تابع به صورت زیر کار می‌کند:

  • register_view با یک درخواست GET فراخوانی می‌شود.
  • ما یک نمونه از فرم را با استفاده از دستور register_form = UserCreationForm() ایجاد می‌کنیم تا بعدا بتوانیم از آن در template استفاده کنیم.
  • زمانی که کاربر فرم را با استفاده از متد POST ارسال کرد ما یک نمونه جدید همراه با داده‌های ذخیره شده ایجاد می‌کنیم:

register_form = UserCreationForm(request.POST)

  • در مرحله بعد معتبر بودن فرم را بررسی خواهیم کرد. اگر فرم معتبر باشد (ورودی‌ها) فرم ما ذخیره خواهد شد و در نهایت به صفحه ورود کاربر را ارجاع می‌دهد در غیر اینصورت صفحه بازسازی خواهد شد.

حال که ما ویو مربوط به فرم عضویت خود را ایجاد کردیم نیاز است که این ویو را به بخش urls.py مربوط به اپلیکیشن‌مان اضافه کنیم. برای این کار در بخش مربوطه قطعه کد زیر را اضافه کنید:

from django.urls import path
from . import views
urlpatterns = [
    path('register/', views.register_view, name='register'),
]

حال همانگونه که مشاهده می‌کنید می‌توانیم به فرم عضویت خودمان از طریق آدرس register/ دسترسی پیدا کنیم. اما پیش از اینکه این مسئله را امتحان کنیم بیایید یک template را به صفحه اضافه کنیم. ابتدا یک دایرکتوری جدید را در اپلیکیشن‌تان با نام templates ایجاد کنید بعد از آن فایل register.html را در آن دایرکتوری قرار دهید.

حال قطعه کد زیر را در فایل html وارد کنید:

<!Doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Register</title>
    </head>
    <body>
       <div class="wrapper">
            <form method="POST">
                {{register_form.as_p}}
                <button type="submit">Register</button>
                {% csrf_token %}
            </form>
        </div>
    </body>
</html>

همانطور که می‌توانید مشاهده کنید در این فایل ما از register_form استفاده کرده‌ایم که در قدم‌های قبلی در view اپلیکیشن آن را با نمونه‌گیری از فرم‌های جنگو ایجاد کردیم. فرم ما ما متد POST ارسال خواهد شد و همچنین می‌توانید شاهد استفاده از تگ {% csrf_token %} نیز باشید. این تگ فرم ما را در مقابل حملات CSRF مصون می‌دارد.

حال زمان آن است که اپلیکیشن‌مان را اجرا کرده و وارد صفحه http://127.0.0.1:8000/register/ در مرورگر شویم. در نهایت شما باید صفحه‌ای مانند تصویر زیر را مشاهده کنید:

ایجاد ویو مربوط به ورود یا Login View

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

برای انجام این کار بجای آنکه از فرم‌های جنگو استفاده کنیم قصد داریم خودمان فرم دستی را درست کنیم. بنابراین برای ایجاد فرم به صورت دستی نیاز داریم که یک فایل جدید با نام forms.py در دایرکتوری اپلیکیشن اصلی ایجاد کنیم. بعد از ایجاد این فایل کدهای زیر را در آن قرار دهید.

from django import forms

class LoginForm(forms.Form):
    username = forms.CharField(label='')
    password = forms.CharField(label='',widget=forms.PasswordInput)

    def __init__(self,*args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['username'].widget.attrs.update({'placeholder':'Username'})
        self.fields['password'].widget.attrs.update({'placeholder':'Password'})

کارهایی که در این قطعه کد انجام داده‌ایم عبارت هستند از موارد زیر:

  • دو فیلد جدید با نام username و password ایجاد کردیم.
  • Label هر کدام از این فیلدها را خالی گذاشتیم.
  • مقدار Placeholder را نیز برابر با هر کدام از ورودی‌ها مقداردهی کردیم.

حال در مرحله دوم قصد داریم که فرایند احرازهویت از طریق دکوراتور پایتونی را شروع کنیم. برای انجام این کار یک فایل جدید در داخل اپلیکیشن خود ایجاد کرده و نام آن را decorator.py قرار دهید.

حال فایل را باز کرده و قطعه کد زیر را در آن قرار دهید:

from django.contrib.auth import authenticate
from django.shortcuts import render
from .forms import LoginForm
from django.http import HttpResponse
from django.contrib import messages

def authenticate_user(login_func):
    def wrapper(request, user=None):
        if request.user.is_authenticated:
            return HttpResponse('You have been Authenticated')
        if request.method == 'POST':
            login_form = LoginForm(request.POST)
            if login_form.is_valid():
                cd = login_form.cleaned_data
                user = authenticate(username=cd['username'], password=cd['password'])
                if user is not None:
                    if user.is_active:
                        return login_func(request,user)
                    else:
                        messages.error(request, 'User is disabled')
                else:
                    messages.error(request, 'User does not exit')
            else:
                messages.error(request, 'Invalid username of passoword')
        else:
            login_form = LoginForm()
        return render(request, 'login.html', {'login_form': login_form})
    return wrapper

تابع اصلی ما که در قطعه کد بالا حکم همان دکوراتور را دارد کارهای زیر را انجام می‌دهد:

  • اگر تابع ما با یک درخواست GET فراخوانی شود ما یک نمونه جدید از LoginForm() را در login_form قرار خواهیم داد. این کار برای نمایش فرم ورودی در داخل Template انجام می‌شود.
  • زمانی که کاربر فرم را با متد POST ارسال کرد ما ابتدا فرم Login را با داده‌های ارسالی در login_form نمونه برداری می‌کنیم.
  • اگر فرم معتبر بود فرایند احراز هویت انجام شود در غیر اینصورت خطاهای معقول نشان داده شود و یا اینکه در نهایت صفحه ورود از اول برگشت داده شود.
  • در صورتی که فرم معتبر بود اما فرایند احراز هویت با مشکل برخورد سناریو‌های مختلفی پیش خواهد رفت.

حال که ما دکوراتور خود را ایجاد کردیم نیاز است که از آن در بخش View مربوط به اپلیکیشن استفاده کنیم. برای این کار وارد فایل authApp/views.py شده و قطعه کد زیر را اضافه کنید:

from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect
from django.contrib.auth import login
from django.http import HttpResponse
from .decorator import authenticate_user

def register_view(request):
    #...

@authenticate_user
def login_view(request, user=None):
    login(request, user)
    return HttpResponse('{} you have logged in successfully'.format(request.user)) 

کاری که تابع login_view انجام می‌دهد این است که در صورتی که کاربر به صورت موفقیت آمیز (موفقیت آمیز بودن براساس دکوراتور authenticate_user اتفاق می‌افتد) فرایند ورود را انجام داد یک HttpResponse به وی برگشت داده خواهد شد.

حال برای استفاده و تست درستی این مسئله بیایید به این ویو در بخش urls.py آدرس بدهیم. برای این کار خط کد زیر را به فایل authApp/urls.py اضافه کنید:

from django.urls import path
from . import views
urlpatterns = [
    #...
    path('login/', views.login_view, name='login'),
]

حال می‌توانیم با استفاده از آدرس /login به url خود دسترسی داشته باشیم.

اما پیش از آنکه در مرورگر این مسئله را بررسی کنیم بیایید یک template جدید برای این بخش از برنامه ایجاد کنیم. برای این کار در دایرکتوری template یک فایل جدید با نام login.html ایجاد کرده و کدهای زیر را در آن قرار دهید:

<!Doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Login</title>
    </head>
    <body>
       <div class="wrapper">
            {% if messages %}
                <ul class="messages">
                    {% for message in messages %}
                    <li>{{ message }}</li>
                    {% endfor %}
                </ul>
            {% endif %}
            <form action="{% url 'login' %}" method="POST">
                {{login_form.as_p}}
                <button type="submit">Login</button>
                {% csrf_token %}
            </form>
        </div>
    </body>
</html>

کاری که در این قطعه کد انجام داده‌ایم عبارت است از:

  • بررسی وجود پیامی به درخواست request – در صورتی که پیامی وجود داشته باشد همه آن‌ها را با حلقه for نشان خواهیم داد.
  • بعد از آن ما یک فرم را ایجاد می‌کنیم که کاربران بتوانند با متد POST درخواست‌شان را ارسال کنند.
  • بعد از آن ما فرمی که در مراحل قبل ایجاد کردیم را به نمایش می‌گذاریم. این کار را با استفاده از متغیر login_form که قبلا از فرم جنگو نمونه برداری شده بود انجام می‌دهیم.
  • همچنین هیچگاه نباید {% csrf_token %} را برای جلوگیری کردن از حملات CSRF فراموش کنید.

زمانی که تمام این مراحل را انجام دادید نوبت اجرای اپلیکیشن و باز کردن آدرس http://127.0.0.1:8000/login/ در مرورگر است. شما در نهایت باید صفحه‌ای مانند تصویر زیر را مشاهده کنید.

حال می‌توانید به خوبی برنامه را تست کرده و هم کاربری را ثبت نام کنید و هم از احراز هویت وی در فرم login بهره بگیرید.

در پایان

در این مقاله از وبسایت راکت سعی کردیم فرایند احراز هویت کاربران در فریمورک جنگو را با استفاده از دکوراتورها در پایتون به شما آموزش دهیم. ابدا مسئله پیچیده‌ای نبوده و به راحتی تنها با مطالعه کدهایی که در این مقاله آورده شده می‌توانید به آسانی این اپلیکیشن را پیاده‌سازی کنید. در صورتی که قصد دارید دانش خودتان از جنگو را افزایش دهید می‌توانید از دوره آموزشی «آموزش Django» استفاده کنید.

چه امتیازی برای این مقاله میدهید؟

خیلی بد
بد
متوسط
خوب
عالی
5 از 1 رای

/@arastoo
ارسطو عباسی
کارشناس تولید و بهینه‌سازی محتوا

کارشناس ارشد تولید و بهینه‌سازی محتوا و تکنیکال رایتینگ - https://arastoo.net

دیدگاه و پرسش

برای ارسال دیدگاه لازم است وارد شده یا ثبت‌نام کنید ورود یا ثبت‌نام

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید