021-71053903 [email protected] پشتیبانی از شنبه تا چهارشنبه ساعت 9 الی 16

ساخت صفحه فراموشی رمز عبور در جنگو

ساخت صفحه فراموشی رمز عبور در جنگو

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

 

مقدمه

سیستم احراز هویت جنگو دارای طیف گسترده ای از ویژگی ها و عملکردهای داخلی است، از جمله توانایی مدیریت مجوزهای کاربران و  مدیریت سیستم رمز های عبوری.

اگر یک کاربر مدیر یا همان ادمین ایجاد کرده اید و به سایت مدیریت جنگو وارد شده اید، احتمالاً امکان تغییر رمز عبور خود را در ادمین مشاهده کرده اید.

صفحه فراموشی رمز عبور در جنگو

صفحه فراموشی رمز عبور در جنگو

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

خب، نماهای احراز هویت جنگو به مدیریت بازنشانی رمز عبور برای کاربران بدون وضعیت کاربر آدمین یا همان ابر کاربر کمک می کند.

در این آموزش، از فرم بازنشانی رمز عبور Django استفاده می کنیم تا به کاربران اجازه دهیم یک ایمیل رمز بازنشانی را برای خود ارسال کنند و سپس به فرم تغییر رمز عبور پیوند داده شود. این به کاربران اجازه می دهد تا در صورت نیاز رمز عبور خود را بازنشانی کنند.

 

توجه: اگر قبلاً سایت خود را برای کاربران پیکربندی نکرده اید، قبل از ادامه این مقاله، راهنمای ثبت نام، ورود و خروج کاربر در جنگو را دنبال کنید. اگر حساب کاربری موجود نداشته باشید، نمی‌توانید بازنشانی رمز عبور را آزمایش کنید.

 

URL های احراز هویت در جنگو

accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']

 

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

 

در فایل Edit mysite > urls.py شروع اضافه کردن کد های زیر کنید:

"""mysite URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include ('main.urls')),
    path('accounts/', include('django.contrib.auth.urls')), #خط کد جدید
]

خط کد جدید را می توانید به صورت جداگانه به فایل خود اضافه کنید !

 

اما به جای اینکه URL ها را به صورت جداگانه فهرست کنیم، فقط می توانیم مسیر “accounts/” را فهرست کنیم.

این مسیر را به فایل urls.py پروژه خود اضافه کنید، در این مورد، فایل mysite > urls.py.

 

فرم‌های فراموشی رمز عبور جنگو

اکنون می توانیم به هر یک از این URL ها در مرورگر دسترسی داشته باشیم. به عنوان مثال، می توانید به URL موجود در تصویر بروید:

فرم‌های فراموشی رمز عبور جنگو

فرم‌های فراموشی رمز عبور جنگو

http://127.0.0.1:8000/accounts/password_reset/

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

بنابراین باید فرم های فراموشی رمز عبور را به قالب های سفارشی که خودمان نوشته ایم متصل کنیم.

اما ابتدا، یک مرور کلی از هر URL هایی که متصل به آن ها است انجام می دهیم.

 

URL ها و قالب های پیش فرض فراموشی رمز عبور جنگو

  • password_reset : به یک فرم ایمیل وصل می شود که یک ایمیل مرتبط با کاربر موجود را درخواست می کند.
  • password_reset_done : پیامی را ارائه می دهد که می گوید ایمیلی با دستورالعمل های بیشتر در مورد نحوه تنظیم مجدد رمز عبور ارسال شده است.
  • password_reset_confirm : فرمی است که برای کاربر رمز عبور جدید درخواست می کند.
  • password_reset_complete : به کاربر می گوید که با رمز عبور جدید وارد شود.

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

 

 

 

یک پوشه رمز عبور حاوی تمام قالب های سفارشی بسازید

برای هر یک از چهار URL، یک الگوی سفارشی ایجاد خواهیم کرد.

برای اهداف سازمانی، بیایید یک پوشه جدید به نام رمز عبور در قالب ها > پوشه اصلی ایجاد کنیم.

در داخل آن، هر یک از قالب های HTML فهرست شده در زیر را اضافه کنید. مراقب باشید اشتباه املایی نداشته باشید.

 

Create password_reset.html

env > mysite > main > templates > main > (New Folder) password > (New File) password_reset.html

{% extends 'main/header.html' %}


{% block content %}

    {% load crispy_forms_tags %}          

    <!--Reset Password-->
    <div class="container p-5">
  	 	<h2 class="font-weight-bold mt-3">Reset Password</h2>
        <hr>
        <p>Forgotten your password? Enter your email address below, and we'll email instructions for setting a new one.</p>
        <form method="POST">
            {% csrf_token %}
            {{ password_reset_form|crispy }}                    
            <button class="btn btn-primary" type="submit">Send email</button>
        </form>
  	</div> 

{% endblock %}

 

Create password_reset_done.html

env > mysite > main > templates > main > password > (New File) password_reset_done.html

{% extends 'main/header.html' %}


{% block content %}

    <!--Password reset sent-->
    <div class="container p-5">
  	<h2 class="font-weight-bold mt-3">Password reset sent</h2>
        <hr>
        <p>We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly.<br>If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder.</p>
  </div>

{% endblock %}

 

 

Create password_reset_confirm.html

env > mysite > main > templates > main > password > (New File) password_reset_confirm.html

{% extends "main/header.html" %}

{% block content %}

  {% load crispy_forms_tags %}  
  
  <!--Password Reset Confirm-->
    <div class="container p-5">
        <h2 class="font-weight-bold mt-3">Password Reset Confirm</h2>
        <hr>
        <p>Please enter your new password.</p>
        <form method="POST">
            {% csrf_token %}
            {{ form|crispy }}                    
            <button class="btn btn-primary" type="submit">Reset password</button>
        </form>
    </div>

{% endblock %}

 

 

Create password_reset_complete.html

env > mysite > main > templates > main > password > (New File) password_reset_complete.html

{% extends "main/header.html" %}

{% block content %} 
  
  <!--Password Reset Complete-->
    <div class="container p-4">
        <h2 class="font-weight-bold mt-3">Password reset complete</h2>
        <hr>
        <p>Your password has been set. You may go ahead and log in now.</p>                 
        <a href="/login" class="btn btn-primary">Log in</a>
    </div>

{% endblock %}

 

 

نکته*:: توجه داشته باشید که همه این الگوها در حال گسترش فایل  header.html هستند این فایل را به عنوان فایل مادر در اختیار دارند که در آن از  CDN  های Bootstrap استفاده شده است. پس دقت کنید که این قایل صدمه ای از لحاظ املایی نبیند.

همچنین از فرم های django-crispy استفاده می کنیم، یک اپلیکیشن Django است که برای استایل سریع فرم های جنگو استفاده می شود.

 

 

اتصال قالب ها را به URL ها

Update mysite > urls.py

env > mysite > mysite > urls.py

"""mysite URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.contrib.auth import views as auth_views #import this


urlpatterns = [
    path('', include ('main.urls')),
    path('admin/', admin.site.urls),
    #path('accounts/', include('django.contrib.auth.urls')),
    path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(template_name='main/password/password_reset_done.html'), name='password_reset_done'),
    path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(template_name="main/password/password_reset_confirm.html"), name='password_reset_confirm'),
    path('reset/done/', auth_views.PasswordResetCompleteView.as_view(template_name='main/password/password_reset_complete.html'), name='password_reset_complete'),      
]

 

اکنون که قالب های سفارشی داریم، باید آنها را به الگوهای URL موجود اختصاص دهیم.

ابتدا اجازه دهید auth_views را در بالای صفحه وارد کنیم:

from django.contrib.auth import views as auth_views #import this

سپس می‌توانیم URL «accounts/» را اضافه کنیم و سه مسیر الگوی جدید دیگر نیز اضافه کنیم که هر template_name را مشخص می‌کند.

path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(template_name='main/password/password_reset_done.html'), name='password_reset_done'), path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(template_name="main/password/password_reset_confirm.html"), name='password_reset_confirm'), path('reset/done/', auth_views.PasswordResetCompleteView.as_view(template_name='main/password/password_reset_complete.html'), name='password_reset_complete'),

اگر همه قالب‌های بازنشانی رمز عبور را در یک پوشه رمز عبور قرار نداده‌اید، template_name شما دارای این قالب «main/password_reset_done.html» خواهد بود.

 

ساخت ایمیل بازنشانی رمز عبور

Create password_reset_email.txt

env > mysite > main > templates > main > password > (New File) password_reset_email.txt

{% autoescape off %}
Hello,

We received a request to reset the password for your account for this email address. To initiate the password reset process for your account, click the link below.

{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

This link can only be used once. If you need to reset your password again, please visit {{ protocol }}://{{domain}} and request another reset.

If you did not make this request, you can simply ignore this email.

Sincerely,
The Website Team

{% endautoescape %}

 

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

Add a reset password URL to the main > urls.py

env > mysite > main > urls.py

from django.urls import path
from . import views

app_name = "main"   


urlpatterns = [
    path("", views.homepage, name="homepage"),
    ...
    path("password_reset", views.password_reset_request, name="password_reset")
]

 

اکنون، برای ارسال ایمیل به کاربر، باید یک نمای password_reset اضافه کنیم که به قالب متصل می‌شود، اما به ما امکان می‌دهد از طریق تابع view ایمیل ارسال کنیم.

مسیر password_reset را به فایل main > urls.py اضافه کنید. اگر فایل اصلی > urls.py ندارید، از راهنمای شروع سریع جنگو برای تنظیمات اولیه دیدن کنید.

 

ارسال ایمیل رمز عبور بازنشانی از طریق فایل views.py

env > mysite > main > views.py

from django.shortcuts import render, redirect
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.models import User
from django.template.loader import render_to_string
from django.db.models.query_utils import Q
from django.utils.http import urlsafe_base64_encode
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes



def password_reset_request(request):
    if request.method == "POST":
        password_reset_form = PasswordResetForm(request.POST)
        if password_reset_form.is_valid():
            data = password_reset_form.cleaned_data['email']
            associated_users = User.objects.filter(Q(email=data))
            if associated_users.exists():
                for user in associated_users:
                    subject = "Password Reset Requested"
                    email_template_name = "main/password/password_reset_email.txt"
                    c = {
                    "email":user.email,
                    'domain':'127.0.0.1:8000',
                    'site_name': 'Website',
                    "uid": urlsafe_base64_encode(force_bytes(user.pk)),
                    "user": user,
                    'token': default_token_generator.make_token(user),
                    'protocol': 'http',
                    }
                    email = render_to_string(email_template_name, c)
                    try:
                        send_mail(subject, email, '[email protected]' , [user.email], fail_silently=False)
                    except BadHeaderError:
                        return HttpResponse('Invalid header found.')
                    return redirect ("/password_reset/done/")
    password_reset_form = PasswordResetForm()
    return render(request=request, template_name="main/password/password_reset.html", context={"password_reset_form":password_reset_form})

 

ما باید یک تابع به فایل view اضافه کنیم، که اگر ایمیل کاربر به یک حساب کاربری موجود متصل شود، یک ایمیل برای کاربر ارسال می کند.

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

آخرین چیزی که اضافه می شود تابع send_mail است که قبل از هدایت کاربر به صفحه /password_reset/done در موضوع، ایمیل، از و به آدرس ها ارسال می شود.

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

لطفاً توجه داشته باشید، اگر از جنگو نسخه 2.1 یا قدیمی‌تر استفاده می‌کنید، باید decode() را به رابط کاربری خود اضافه کنید تا بایت تحت اللفظی از نوع بایت به نوع رشته تبدیل شود.

"uid": urlsafe_base64_encode(force_bytes(user.pk)).decode()

 

پیکربندی settings.py برای ارسال ایمیل

env > mysite > main > settings.py

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

 

اما با دیدن اینکه چگونه فقط در حال آزمایش هستیم، مطمئن شوید که EMAIL_BACKEND فهرست شده در بالا را به فایل تنظیمات اضافه کرده اید تا بتوانیم ایمیل را به CLI ارسال کنیم.

برای تولید، backend به یک سرویس ارسال ایمیل تغییر می کند.

 

 

تست ایمیل بازنشانی رمز عبور

برای دسترسی به صفحه تنظیم مجدد رمز عبور جدید، باید از طریق این ادرس http://127.0.0.1:8000/password_reset می توانید وارد شوید.

 

 

هنگامی که صفحه /password_reset/done را دریافت کردید، CLI خود را باز کنید و باید پیامی مشابه پیام زیر مشاهده کنید.

 

Terminal

[05/Jun/2020 17:07:29] "POST /password_reset HTTP/1.1" 500 80466
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Password Reset Requested
From: [email protected]
To: [email protected]
Date: Sat, 06 Jun 2020 00:11:42 -0000


Hello,

We received a request to reset the password for your account for this email address. To initiate the password reset process for your account, click the link below.

http://127.0.0.1:8000/reset/<uid>/<token>/

This link can only be used once. If you need to reset your password again, please visit http://127.0.0.1:8000 and request another reset.

If you did not make this request, you can simply ignore this email.

Sincerely,
The Website Team


-------------------------------------------------------------------------------

 

 

برای مشاهده صفحه تغییر رمز عبور، باید دقیقاً پیوند ارسال شده به CLI را کپی کرده و در مرورگر خود جایگذاری کنید. سپس رمز عبور جدید خود را وارد کرده و تایید می کنید.

 

 

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

 

 

تنظیم مجدد رمز عبور با استفاده از پیام های جنگو

در مثال بالا، زمانی که فرم password_reset به درستی ارسال شد، تغییر مسیر را به صفحه /password_reset/done اضافه کردیم، اما در عوض، می‌توانیم از پیام‌های جنگو برای اطلاع دادن به کاربر مبنی بر ارسال ایمیل به صندوق ورودی خود استفاده کنیم.

برای انجام این کار، ما فقط باید پروژه را برای استفاده از چارچوب پیام های جنگو پیکربندی کنیم و سپس پیام را به تابع view اضافه کنیم.

 

 

یک پیام موفقیت جنگو اضافه کنید

env > mysite > main > views.py

from django.shortcuts import render, redirect
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.models import User
from django.template.loader import render_to_string
from django.db.models.query_utils import Q
from django.utils.http import urlsafe_base64_encode
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes
from django.contrib import messages #import messages

def homepage(request):
    return render (request=request, template_name="main/home.html")

def password_reset_request(request):
    if request.method == "POST":
        password_reset_form = PasswordResetForm(request.POST)
        if password_reset_form.is_valid():
            data = password_reset_form.cleaned_data['email']
            associated_users = User.objects.filter(Q(email=data))
            if associated_users.exists():
                for user in associated_users:
                    subject = "Password Reset Requested"
                    email_template_name = "main/password/password_reset_email.txt"
                    c = {
                    "email":user.email,
                    'domain':'127.0.0.1:8000',
                    'site_name': 'Website',
                    "uid": urlsafe_base64_encode(force_bytes(user.pk)),
                    'token': default_token_generator.make_token(user),
                    'protocol': 'http',
                    }
                    email = render_to_string(email_template_name, c)
                    try:
                        send_mail(subject, email, '[email protected]' , [user.email], fail_silently=False)
                    except BadHeaderError:

                        return HttpResponse('Invalid header found.')
                        
                    messages.success(request, 'A message with reset password instructions has been sent to your inbox.')
                    return redirect ("main:homepage")
    password_reset_form = PasswordResetForm()
    return render(request=request, template_name="main/password/password_reset.html", context={"password_reset_form":password_reset_form})

ابتدا نحوه استفاده از چارچوب پیام‌های جنگو را ببینید تا پیکربندی‌های پروژه لازم برای پیام‌های جنگو را یاد بگیرید، سپس یک پیام موفقیت آمیز قبل از بازگشت اضافه کنید که اکنون به جای password_reset/done به صفحه اصلی هدایت می‌شود.

فایل را ذخیره کنید.

سپس می توانید password_reset_done.html و الگوی URL آن الگو را حذف کنید.

اکنون زمانی که کاربر فرم بازنشانی رمز عبور را ارسال می کند، به جای الگو پیامی ظاهر می شود.

 

یک پیام خطای جنگو اضافه کنید

File views.py

env > mysite > main > views.py

from django.shortcuts import render, redirect
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.models import User
from django.template.loader import render_to_string
from django.db.models.query_utils import Q
from django.utils.http import urlsafe_base64_encode
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes
from django.contrib import messages #import messages

def homepage(request):
    return render (request=request, template_name="main/home.html")

def password_reset_request(request):
    if request.method == "POST":
        password_reset_form = PasswordResetForm(request.POST)
        if password_reset_form.is_valid():
            data = password_reset_form.cleaned_data['email']
            associated_users = User.objects.filter(Q(email=data))
            if associated_users.exists():
                for user in associated_users:
                    subject = "Password Reset Requested"
                    email_template_name = "main/password/password_reset_email.txt"
                    c = {
                    "email":user.email,
                    'domain':'127.0.0.1:8000',
                    'site_name': 'Website',
                    "uid": urlsafe_base64_encode(force_bytes(user.pk)),
                    'token': default_token_generator.make_token(user),
                    'protocol': 'http',
                    }
                    email = render_to_string(email_template_name, c)
                    try:
                        send_mail(subject, email, '[email protected]' , [user.email], fail_silently=False)
                    except BadHeaderError:

                        return HttpResponse('Invalid header found.')
                        
                    messages.success(request, 'A message with reset password instructions has been sent to your inbox.')
                    return redirect ("main:homepage")
            messages.error(request, 'An invalid email has been entered.')
    password_reset_form = PasswordResetForm()
    return render(request=request, template_name="main/password/password_reset.html", context={"password_reset_form":password_reset_form})

 

همچنین می توانید انتخاب کنید که یک پیام خطا خارج از شرط if که در صورت عدم وجود کاربر مرتبط در پایگاه داده ظاهر می شود، را اضافه کنید.

جمع بندی نهایی

خوب همانطوری که دیدی ما با استفاده از فریم ورک جنگو و با استفاده از Bootstrap به راحتی توانستیم یک سیستم مدیریت فراموشی رمز عبوری کاربران را ثبت کنیم. امیدوارم از این مقاله حداکثر استفاده را کرده باشید.

محمدرضا حسنی

224 مطلب منتشر شده

دانش آموخته رشته فناوری اطلاعات / موسس پایتونی ها

درباره این مطلب نظر دهید !

مطالب پرمخاطب پایتونی ها

محصولات فروش پایتونی ها

%60
تخفیف

آموزش فیگما (Figma)

30,000 تومان
3
%69
تخفیف

آموزش برنامه نویسی پایتون

35,000 تومان
2