Password Recover
Recover password functionality with e-mail sender usign Django Email Backend
How to start project.
- Create a folder in your machine
- Create a virtual environment
- python3 -m venv venv
- Start the virtual environment
. venv/bin/activate
(Linux)venv/Scripts/Activat
e (Windows)
- Inside your venv folder clone the project
git clone https://github.com/alexlopesbr/forgot-password.git
- In your-new-folder/venv/forgot-password
pip install -r requirements.txt
to install the project's dependenciespython manage.py migrate
to generate your databasepython3 manage.py createsuperuser
to create the adminpython3 manage.py runserver
to start the server
- Open your browser and go to http://127.0.0.1:8000/admin/
- Login with the admin credentials
- Now you can see you user and some info in admin panel
Using the functionality
We have two POST requests:
{{localhost}}/core/user/forgot-password/
Send an e-mail with a link to recover the password.
body of the request:
{
"email": "email from you user created"
}
{{localhost}}/core/user/change-forgotten-password/
Allows you to enter the new password.
body of the request:
{
"email": "email from you user created",
"forgot_password_hash": "inside the redefine you passwod button sended to your email",
"new_password": "set a new password"
}
You can use Postman or Insomnia to test the requests.
Note: When you start your server the localhost generaly is http://127.0.0.1:8000/.
Some instructions and informations
root
setings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BASE_URL = 'sandbox.com'
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'your-key'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
First step, set some configures in settings.py. Don't forget to set the EMAIL_HOST_USER and the EMAIL_HOST_PASSWORD.
core
views.py
from core.models import User
from rest_framework.response import Response
from .services import send_forgot_password_email
from .exceptions import ForgotPasswordInvalidParams
from rest_framework.permissions import AllowAny
from rest_framework.decorators import action
@action(detail=False, methods=['post'], url_path='forgot-password', permission_classes=[AllowAny])
def forgot_password(self, request):
if 'email' not in request.POST:
raise ForgotPasswordInvalidParams
send_forgot_password_email(request.POST['email'])
return Response({'worked': True})
@action(detail=False, methods=['post'], url_path='change-forgotten-password', permission_classes=[AllowAny])
def change_forgotten_password(self, request):
email = request.POST.get('email', None)
forgot_password_hash = request.POST['forgot_password_hash']
new_password = request.POST['new_password']
User.change_password(email, forgot_password_hash, new_password)
return Response({'worked': True})
Here we create a request called
forgot-password
to send an email with a link to change the password.
In this case, we are calling thesend_forgot_password_email
function. (see the function details below)
We also create a
change-forgotten-password
request to change the password. Here we need to send the email, the hash and the new password.Obs. the hash is an inplicit parameter that is generated by the
send_forgot_password_email
function.
forgot_password_hash and new_password fields are set in core.models.py
services.py
from core.models import User
from emails.services import send_email_forgot_password
from core.exceptions import UserDoesNotExist
from django.utils import timezone
from datetime import timedelta
import re
import urllib.parse
def send_forgot_password_email(email):
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
raise UserDoesNotExist
now = timezone.now()
user.forgot_password_hash = re.sub(r'\D', '', str(now))
user.forgot_password_expire = now + timedelta(hours=24)
user.save()
link = 'https://forgot-password.com/change-password?email=%s&hash=%s' % (
urllib.parse.quote(user.email), user.forgot_password_hash)
send_email_forgot_password(user.email, link)
In this function we gererate a hash with a simple
timezone.now()
that will be atribuate toforgot_password_hash
. This will be our validator.
We also set theforgot_password_expire
field with the sametimezone.now()
plus thetimedelta
of 24 hours. So we give to user 24 hours to change the password.
We can bring another informations like the name of the user, but we don't use it in this exemple.
In the
send_email_forgot_password
function we send the email with the link to change the password.
emails
services.py
from django.core.mail import EmailMessage
from django.conf import settings
def open_and_return(my_file):
with open(settings.BASE_DIR + '/emails/templates/' + my_file, 'r', encoding="utf-8") as file:
data = file.read()
return data
def send_email_forgot_password(email, link):
template = open_and_return("forgot-password.html").format(link)
msg = EmailMessage(
u'Email forgot password received',
template,
to=[email, ],
from_email=settings.EMAIL_HOST_USER
)
msg.content_subtype = 'html'
msg.send()
The last step is sending the email with the link to user to change the password.
open_and_return
function opens the template and returns the content.
This template is inemails/templates/forgot-password.html
and will be used to lets our email message prettier.
Intemplate = open_and_return("forgot-password.html").format(link)
we replace thelink
with the link that was setted in thesend_forgot_password_email
function.
More information about sending emails in Django documentation