I have django app with authentication and email verification in it. First, user enters credentials in form, then I send him an email with link to verification. And now I get an error. When user clicks on link in mail it says that token is not recognized.
from .utils import generate_token
class PersonalRegister(View):
def post(self, request, *args, **kwargs):
...
#get data from form using request.POST.get
#sends email
current_site = get_current_site(request)
email_subject = 'Activate account | Zane'
email_body = render_to_string('authentication/email/email_body.html', {
'user': models.PersonalUser,
'domain': current_site,
'uid': urlsafe_b64encode(force_bytes(user.pk)),
'token': generate_token.make_token(user)
})
email = EmailMessage(subject=email_subject, body=email_body, from_email=settings.EMAIL_FROM_USER, to=[user.email])
email.send()
...
def get(self, request, *args, **kwargs):
return render(request, 'authentication/personal/personal_signup.html')
From .utils I have imported that function:
from time import time
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_email_verified))
generate_token = TokenGenerator()
In render_to_string I have this file
email_body.html
{% autoescape off %}
Hi {{mail}}
Please use the link below to verify your account.
http://{{domain}}{% url 'activate' uidb64=uid token=token %}
{% endautoescape %}
So when user clicks on this email it takes him to site which triggers another function:
urls.py
from django.urls import path
from .views import (
Login,
PersonalRegister,
logout_user,
activate_user
)
urlpatterns = [
path('login/', Login.as_view(), name='login'),
path('register/', PersonalRegister.as_view(), name='register'),
path('logout/', logout_user, name='logout'),
path('activate-user/<uidb64>/<token>/', activate_user, name='activate')
]
function
def activate_user(request, uidb64, token):
try:
uid = force_str(urlsafe_b64decode(uidb64))
user = models.PersonalUser.objects.get(pk=uid)
except Exception as e:
user = None
if user and generate_token.check_token(user, token):
user.is_email_verified = True
user.save()
messages.add_message(request, messages.SUCCESS,
'Email verified, you can now login')
return redirect(reverse('login'))
return render(request, 'authentication/email/activate-failed.html', {"user": user})
activate-failed.html
<p>Someone went wrong with your link</p>
I want to trigger if function in my activate_user function, so it will verify users email.
Related
I am attaching my code in views and urls.py. Whenever the server runs, I want to see the login page first, but I am seeing an error that this page is not working.
#views.py
def loginPage(request):
if request.user.is_authenticated:
return redirect('/')
else:
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('/')
else:
messages.info(request, 'Username OR password is incorrect')
context = {}
return render(request, 'accounts/login.html', context)
# urls.py
urlpatterns = [
path('', views.loginPage, name="login"),
path('index/',views.index,name="index"),
You should pass #login_required decorator in your view. If you don't want to pass this decorator in your every view there are second way which you can do using middleware. In middleware you check the user is authenticated or not. If yes it redirects user to index page other way to login page. Here is an example:
Create middleware.py file and write this code inside it:
from django.utils.deprecation import MiddlewareMixin
from django.urls import reverse
from django.shortcuts import redirect
class LoginCheckMiddleWare(MiddlewareMixin):
def process_view(self, request, view_func, view_args, view_kwargs):
modulename = view_func.__module__
user = request.user # Who is the current user ?
if user.is_authenticated:
return redirect(reverse('index-page'))
else:
if request.path == reverse('login_page') or modulename == 'django.contrib.auth.views':
pass
else:
return redirect(reverse('login_page'))
After that add this line inside MIDDLEWARE in settings.py file:
'folder.middleware.LoginCheckMiddleWare', instead of folder write your middleware file located folder
#action(detail=True, methods=['get'], url_path='password-reset/<uid64>/<token>', url_name='password-reset-confirm')
def password_reset(self, request, uid64, token):
pass
this is the url ( http://localhost:8000/user/2/password-reset/Mg/az44bk-48c221372ceaca98b4090a421131d5f3 ) I am trying to reach, but it keeps returning 404 page not found
Update::
urls file:
from django.urls import path
from django.urls.conf import include
from .views import UserViewset, CompanyViewset, ProfileViewset
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('user', UserViewset, basename='user')
router.register('company', CompanyViewset, basename='company')
router.register('profile', ProfileViewset, basename='profile')
urlpatterns = [
path('', include(router.urls)),
path('<int:id>', include(router.urls)),
]
views file:
#action(detail=True, methods=['post'], url_path='request-reset-email', url_name='request-reset-email')
def request_reset_password_email(self, request, pk):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
email = serializer.data.get('email')
user = self.get_object()
if email == user.email:
token = PasswordResetTokenGenerator().make_token(user)
current_site = get_current_site(request=request).domain
relativeLink = '/user/' + str(user.id) + '/password-reset/' + token
absurl = 'http://'+current_site + relativeLink
email_body = 'Hello \n Use link below to reset your password \n' + absurl
subject = 'Reset your password'
send_mail(subject, email_body, EMAIL_HOST_USER, [
user.email], fail_silently=False)
return Response({'success': 'we have sent you an email'}, status=status.HTTP_200_OK)
return Response({'failed': 'email does not match'}, status=status.HTTP_404_NOT_FOUND)
#action(detail=True, methods=['patch'], url_path=r'password-reset/(?P<token>\w+)', url_name='password-reset-confirm')
def set_new_password(self, request, pk, token):
user = self.get_object()
if not PasswordResetTokenGenerator().check_token(user, 'az569s-6ad4e11c2f56aa496128bc1c923486cb'):
return Response({'error': 'Token is not valid'}, status=status.HTTP_401_UNAUTHORIZED)
serializer = self.get_serializer(data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
password = serializer.data.get('password')
user.set_password(password)
user.save()
return Response({'success': 'success'})
serializers
class ResetPasswordEmailRequestSerializer(serializers.Serializer):
email = serializers.EmailField()
class SetNewPasswordSerializer(serializers.Serializer):
password = serializers.CharField(min_length=6, max_length=20)
Recently I have removed the uid64 since I am not using it, tested everything and it does work when hardcode the token in the url
Try this:
#action(
detail=True,
methods=['get'],
url_path=r'password-reset/(?P<uid64>\w+)/(?P<token>\w+)',
url_name='password-reset-confirm'
)
def password_reset(self, request, pk, uid64, token):
pass
You will have to capture the three parameters: pk, uid64, and token
Views.py(name of app: userprofileinfo)
from django.shortcuts import render
from userprofileinfo.forms import UserForm
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect, HttpResponse
from django.contrib.auth import authenticate, login, logout
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.views import View
from django.contrib import messages
from django.core.mail import send_mail
from django.contrib.sites.shortcuts import get_current_site
from django.utils.encoding import force_bytes, force_text, DjangoUnicodeDecodeError
from django.core.mail import send_mail
from django.contrib.sites.shortcuts import get_current_site
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
from django.template.loader import render_to_string
from .utils import account_activation_token
from django.urls import reverse
from django.contrib import auth
#login_required
def special(request):
return HttpResponseRedirect("You are logged in, Nice!")
#login_required
def userlogout(request):
logout(request)
return HttpResponseRedirect(reverse('careforallapp:base'))
def register(request):
registered = False
if request.method == "POST":
user_form = UserForm(data=request.POST)
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.is_active = False
user.save()
email = UserForm('email')
current_site = get_current_site(request)
email_body = {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
}
link = reverse('userprofileinfo:activate', kwargs={
'uidb64': email_body['uid'], 'token': email_body['token']})
email_subject = 'Activate your account'
activate_url = 'http://'+current_site.domain+link
send_mail(
email_subject,
'Hi '+user.username + ', Please the link below to activate your account \n'+activate_url,
'settings.EMAIL_HOST',
[user.email],
fail_silently=False
)
return HttpResponseRedirect(reverse('careforallapp:base'))
else:
print(user_form.errors)
else:
user_form = UserForm()
return render(request,'userprofileinfo/registration.html',
{'user_form':user_form,
'registered':registered})
class VerificationView(View):
def get(self, request, uidb64, token):
try:
id = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=id)
if not account_activation_token.check_token(user, token):
return redirect('login'+'?message='+'User already activated')
if user.is_active:
return redirect('login')
user.is_active = True
user.save()
messages.success(request, 'Account activated successfully')
return redirect('login')
except Exception as ex:
pass
return HttpResponseRedirect(reverse('userprofileinfo:userlogin'))
def userlogin(request):
if request.method == "POST":
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username = username, password = password)
if user:
if user.is_active:
login(request, user)
return HttpResponseRedirect(reverse('careforallapp:base'))
else:
return HttpResponse("ACCOUNT NOT ACTIVE")
else:
print("Someone tried to login and failed!")
print("Username: {} and password: {}".format(username, password))
return HttpResponse("invalid login details")
else:
return render(request, 'userprofileinfo/login.html', {})
.env
export EMAIL_HOST_PASSWORD=*******
export EMAIL_HOST_USER = careall249#gmail.com
export EMAIL_HOST=smtp.gmail.com
urls.py
from django.conf.urls import url
from django.urls import path
from .views import VerificationView
from userprofileinfo import views
app_name = 'userprofileinfo'
urlpatterns = [
url(r'^login/', views.userlogin, name='userlogin'),
url(r'^register/', views.register, name='register'),
url(r'^logout/', views.userlogout, name='userlogout'),
url(r'^special/', views.special, name='special'),
path('activate/<uidb64>/<token>', VerificationView.as_view(), name='activate'),
]
Can someone go through the code. Login page, registration page all working fine but verification link is not working, when user register, he gets the link on his Gmail but when he presses the link for verify nothing happens. User not get active. Can somebody go through it and find the error.
When logging into my app, the user is not authenticating correctly.
Views.py
'''
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import authenticate, login
from django.urls import reverse
from users.forms import CustomUserCreationForm
from django.http import HttpResponse
from users.models import Blog
from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth.decorators import login_required
# Create your views here.
def intro(request):
return render(request, "intro.html")
def logmein(request):
return render(request, "logmein.html")
def login(request):
username1 = request.POST.get('username')
password1 = request.POST.get('password')
user = authenticate(request, username=username1, password=password1)
login(user, request)
if user.is_authenticated:
return render(request, "users/mainmenu.html")
else:
return render(request, "intro.html")
def mainmenu(request):
return render(request, "users/mainmenu.html")
'''
Mainmenu.html
'''
{% extends 'base.html' %}
{% block content %}
<h2>MainMenu</h2>
Hello, {{ user.username }}
{% endblock %}
'''
When mainmenu.html is displayed following login, the user.username is showing as the SuperUser, regardless
of what username and password is used to login.
try this:
from django.contrib.auth import login as auth_login
def login(request):
username1 = request.POST.get('username')
password1 = request.POST.get('password')
user = authenticate(username=username, password=password)
if not user: # authentication fails
messages.error(request, 'error')
return render(request, "intro.html")
# login success
auth_login(request, user)
messages.success(request, 'success')
return render(request, "users/mainmenu.html")
When trying to access a private page, this view redirects to the login page if the user is not authenticated, and after the authentication was done, I wanted it to redirect to the private page instead of success_url, with LoginView configured for a FormView. When I access the private page without logging in, this standard url is generated according to django
http://localhost/myapp/login/?next=/myapp/private-page/,
in this case the url that will be redirected after login should be myapp/private-page instead of success_url
My code looks like this:
# myapp/urls
from django.urls import path
from . import views
app_name = 'myapp'
urlpatterns = [
path("", views.home, name='home'),
path("login/", views.LoginRequest.as_view(), name='login'),
path('logout/', views.logout_request, name='logout'),
path("signup/", views.signup, name='signup'),
path("private-page/", views.PrivatePage.as_view()),
]
# myapp/views.py
class PrivatePage(LoginRequiredMixin, TemplateView):
template_name = 'myapp/private-page.html'
login_url = 'myapp:login'
class LoginRequest(FormView):
template_name = 'myapp/auth/login/login.html'
form_class = LoginForm
success_url = 'myapp:home'
def form_valid(self, form):
"""If the form is valid, redirect to the supplied URL."""
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(self.request, user)
messages.info(self.request, f'You are connected as {username}')
# here the code to redirect to the private-page
# instead this return
return redirect(self.get_success_url())
else:
self.form_invalid(form)
def form_invalid(self, form):
"""If the form is invalid, render the invalid form."""
for key in form.errors:
messages.error(self.request, form.errors[key])
return self.render_to_response(self.get_context_data(form=form))