I was making a web app on Django. I tried to send an email verification link to any new user who registers on my website. The thing works fine when I am hosting it on localhost but upon hosting on AWS Elastic Beanstalk the email verification shows an invalid token.
models.py
from django.contrib.auth.models import User
from django.db import models
# Create your models here.
from django.utils.safestring import mark_safe
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.CharField(blank=True, max_length=20)
address = models.CharField(blank=True, max_length=150)
city = models.CharField(blank=True, max_length=20)
PINcode = models.IntegerField(blank=True, null=True)
country = models.CharField(blank=True, max_length=50)
image = models.ImageField(blank=True, default="Users/profile.png", upload_to='images/users/')
def __str__(self):
return self.user.username
def user_name(self):
return self.user.first_name + ' ' + self.user.last_name + ' [' + self.user.username + '] '
def image_tag(self):
return mark_safe('<img src="{}" height="50"/>'.format(self.image.url))
image_tag.short_description = 'Image'
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import User
from django.forms import TextInput, EmailInput, Select, FileInput
from user.models import UserProfile
class SignUpForm(UserCreationForm):
username = forms.CharField(max_length=30,label= 'User Name :')
email = forms.EmailField(max_length=200,label= 'Email :')
first_name = forms.CharField(max_length=100, help_text='First Name', label= 'First Name :')
last_name = forms.CharField(max_length=100, help_text='Last Name', label= 'Last Name :')
class Meta:
model = User
fields = ('username', 'email','first_name','last_name', 'password1', 'password2', )
def __init__(self, *args, **kwargs):
super(SignUpForm, self).__init__(*args, **kwargs)
self.fields["username"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Username", "aria-label": "Username", "aria-describedby": "basic-addon1" }
self.fields["first_name"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "First Name", "aria-label": "First Name", "aria-describedby": "basic-addon1"}
self.fields["last_name"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Last Name", "aria-label": "Last Name", "aria-describedby": "basic-addon1"}
self.fields["email"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Email", "aria-label": "Email", "aria-describedby": "basic-addon1"}
self.fields["password1"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Enter Password", "aria-label": "Enter Password", "aria-describedby": "basic-addon1"}
self.fields["password2"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Confirm Password", "aria-label": "Confirm Password", "aria-describedby": "basic-addon1"}
tokens.py
from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class TokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp) +
six.text_type(user.is_active)
)
account_activation_token = TokenGenerator()
views.py
def registerPage(request):
User = get_user_model()
form = SignUpForm()
if request.method == 'POST':
form = SignUpForm(request.POST, request.FILES)
if form.is_valid():
email = form.cleaned_data.get('email')
if User.objects.filter(email=email).exists():
messages.warning(request, "Signup error!! Invalid email or email already taken")
else:
user = form.save()
user.is_active = False
user.save()
current_site = get_current_site(request)
mail_subject = 'Activate your account.'
message = render_to_string('user/email_template.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('email')
send_mail(mail_subject, message, 'myemail@gmail.com', [to_email], fail_silently=False,)
print(send_mail)
print(to_email)
print(message)
return render(request, 'user/confirm_email.html')
context = {'form': form}
return render(request, 'user/signup_form.html', context)
def activate(request, uidb64, token):
User = get_user_model()
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
return render(request, 'user/email_confirmed.html')
else:
return render(request, 'user/verification_failed.html')
email_template.html
{% autoescape off %}
Hi {{ user.first_name }},
Your username is: {{ user }}
Thank you for creating an account with us Please use link below to confirm your email Id:
"http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
{% endautoescape %}"
Team {{ domain }}
settings.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
.......
if 'RDS_DB_NAME' in os.environ:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.environ['RDS_DB_NAME'],
'USER': os.environ['RDS_USERNAME'],
'PASSWORD': os.environ['RDS_PASSWORD'],
'HOST': os.environ['RDS_HOSTNAME'],
'PORT': os.environ['RDS_PORT'],
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'dbname',
'USER': 'dbuser',
'PASSWORD': 'dbpassword',
'HOST': 'AWSRDSEndpoint',
'PORT': '5432',
}
}
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Asia/Kolkata'
USE_I18N = True
USE_L10N = True
USE_TZ = True
STATIC_URL = '/static/'
STATIC_ROOT = 'static'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'staticfiles')
]
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'myemail@gmail.com'
EMAIL_HOST_PASSWORD = 'mypassword'
MEDIA_URL = '/uploads/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/uploads')
urls.py
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
urlpatterns = [
....
path('signup/', views.registerPage, name='signup_form'),
path('activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
views.activate, name='activate'),
....
]
The verification link generated is valid when hosted on localhost but throws "invalid token" when hosted on the elastic beanstalk.