django how to authenticate user until verify email - django

How to authenticate user until he verify the email?
In my sign up process, I create the User, which means he can login even without verify email. Is there a build-in method to set a un-verified status on a User?

models.py
email_active = models.BooleanField(default=False,
verbose_name=u'Email active ')
views.py
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(username=username, password=password)
if user is not None:
if user.email_active:
login(self.request, user)
return HttpResponse("login success")
else:
return HttpResponse("user email is not active")
else:
return HttpResponse("username or password error")
you can active email by send email with verify_code,user can use verify_code to active their email.
Demo:
models.py:
class EmailVerify(models.Model):
owner = models.ForeignKey(User,
on_delete=models.CASCADE,
verbose_name='owner')
verify_code = models.CharField(max_length=254,
null=True,
verbose_name='verify_code ')
def update(self):
self.verify_code = self.generate_key()
self.save()
return self.verify_code
def get_active_email_url(self, request):
from django.urls import reverse
url = '{}?active_code={}'.format(request.build_absolute_uri(reverse('user_login', args=())), self.verify_code)
return url
#staticmethod
def generate_key():
return binascii.hexlify(os.urandom(20)).decode()
class Meta:
verbose_name = 'EmailVerify'
utils.py :
def send_active_email(request, user):
current_site = get_current_site(request)
site_name = current_site.name
if EmailVerify.objects.filter(owner=user, category=0).exists():
verify = EmailVerify.objects.filter(owner=user).first()
else:
verify = EmailVerify.objects.create(owner=user)
verify.update()
title = u"{} active email".format(site_name)
message = "".join([
u"click this link can active your email:\n\n",
"{}\n\n".format(verify.get_active_email_url(request=request)),
])
try:
send_mail(title, message, settings.DEFAULT_FROM_EMAIL, [user.email])
message = "success"
except ConnectionRefusedError as e:
message = e.strerror
except Exception as e:
message = str(e)
return message
views.py
class LoginView(BaseContextMixin, FormView):
template_name = 'user/login.html'
form_class = LoginForm
success_url = reverse_lazy('index')
def get_context_data(self, **kwargs):
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
if 'active_email' in self.request.GET:
active_email = self.request.GET.get('active_email')
try:
user = User.objects.get(email=active_email, email_active=False)
kwargs['message'] = send_active_email(self.request, user)
except (ObjectDoesNotExist, MultipleObjectsReturned):
kwargs['message'] = 'email not exist or actived'
if 'active_code' in self.request.GET:
active_code = self.request.GET.get('active_code')
try:
email_verify = EmailVerify.objects.get(verify_code=active_code)
email_verify.owner.email_active = True
email_verify.owner.save()
email_verify.delete()
kwargs['message'] = 'email {} actived'.format(email_verify.owner.email)
except ObjectDoesNotExist:
kwargs['message'] = 'unless link'
except MultipleObjectsReturned:
EmailVerify.objects.filter(verify_code=active_code).delete()
kwargs['message'] = 'error!'
return super(LoginView, self).get_context_data(**kwargs)
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
return form_class(request=self.request, **self.get_form_kwargs())
forms.py:
class LoginForm(forms.Form):
active_email = None
username = forms.CharField(label='username')
password = forms.CharField(widget=forms.PasswordInput, label='password')
def __init__(self, request, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.request = request
self.fields['username'].widget.attrs.update({'class': 'form-control',
"placeholder": self.fields['username'].label})
self.fields['password'].widget.attrs.update({'class': 'form-control',
"placeholder": self.fields['password'].label})
def clean(self):
username = self.cleaned_data["username"]
password = self.cleaned_data["password"]
user = authenticate(username=username, password=password)
if user is not None:
if user.email_active:
login(self.request, user)
else:
self.active_email = user.email
self.add_error("username", "not active")
else:
self.add_error("username", "username or password error")
login.html:
{% extends "user/user_base.html" %}
{% block content %}
<div class="login-box">
<div class="login-logo">
{{ website_title|default_if_none:'' }}
</div>
<div class="login-box-body">
<form method="post" action="{% url 'user_login' %}" class="form">
{% csrf_token %}
{% for field in form %}
<div class="form-group no-margin {% if field.errors %} has-error {% endif %}">
<label class="control-label" for="{{ field.id_for_label }}">
<b>{{ field.label }}</b>
{% if message %}
{% ifequal field.name 'username' %}{{ message }}{% endifequal %}
{% endif %}
{% if field.errors %}
{{ field.errors.as_text }}
{% ifequal field.errors.as_text '* not active' %}
<a href="{% url 'user_login' %}?active_email={{ form.active_email }}">
send active emial
</a>
{% endifequal %}
{% endif %}
</label>
{{ field }}
</div>
{% endfor %}
<div class="row">
<div class="col-md-6">
<button id="btn_login" type="submit" style="width: 100%"
class="btn btn-raised btn-primary">Login
</button>
</div>
</div>
</form>
</div>
</div>
{% endblock %}

Related

authenticate() is not validate data properly django

When I try to click on login button it always execute the invalid credentials instead of redirect to the index page.. What I did is that in database create table name signup and wants to validate all the data from that table.. Here signup_data function is works well but in login_data cannot authenticate the user.
Models.py
from django.db import models
class signup(models.Model):
username = models.CharField(max_length=10)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
email = models.EmailField()
password = models.CharField(max_length=10)
Forms.py
from django.forms import ModelForm
from . models import signup
from django import forms
class signupform(ModelForm):
username= forms.CharField(max_length=10,widget=forms.TextInput(attrs={'class':'form-control'}))
first_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(max_length=20,widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(max_length=20,widget=forms.EmailInput(attrs={'class': 'form-control'}))
password = forms.CharField(max_length=10,widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model = signup
fields = '__all__'
Views.py
from django.shortcuts import render,redirect
from . forms import signupform
from . models import signup
from django.contrib import messages
from django.contrib.auth import login,authenticate
def index(response):
return render(response,'login_module/index.html')
def signup_data(response):
if response.method == 'POST':
form = signupform(response.POST)
if form.is_valid():
username = form.cleaned_data['username']
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
if signup.objects.filter(username=username).exists():
# messages.add_message(response,messages.WARNING,'Username is already taken')
messages.error(response,'Username is already taken')
return redirect('signup')
elif signup.objects.filter(email=email).exists():
messages.error(response,'Email is already taken')
# messages.add_message(response,messages.WARNING,'Email is already taken')
return redirect('signup')
else:
register_instance = signup(username=username, first_name=first_name, last_name=last_name, email=email, password=password)
register_instance.save()
messages.success(response,'Registered Successfull')
return redirect('signup')
else:
form = signupform()
return render(response,'login_module/signup.html',{'form':form, 'message': messages})
def login_data(request):
form = signupform(request.POST or None)
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
return redirect('index')
else:
messages.error(request,'Invalid Credentials')
return redirect('login')
else:
return render(request,'login_module/login.html',{'form':form, 'message': messages})
Login.html
{% extends 'login_module/base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12 text-center mt-50">
<h1>Login Page</h1>
</div>
</div>
<div class="row">
<div class="col-md-4 offset-md-4 ">
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group rounded-top">
{{ form.username.label_tag }} {{ form.username }}
</div>
<div class="form-group rounded-top">
{{ form.password.label_tag }} {{ form.password }}
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Login</button>
</div>
</form>
</div>
</div>
<div class="text-center mt-50">
{% if messages %}
{% for message in messages %}
<div class="alert alert-danger" role="alert">
{{ message }}
{% endfor %}
{% endif %}
</div>
</div>
{% endblock %}
Login Page
As far as I can tell you are creating a signup object when signing up, but when trying to login with authenticate django is looking for the generic User model. You have to create a User in the database rather than a signup object to use authenticate.

Custom Reset password templates forms doesn't show

I modified the first password reset page successfully. (Where the user insert his email address)
Where it doesn't work it the Password Reset Confirm page (Where the users write his new password). When I click the link that I received by email to reset the password, it load my html template but it doesn't load my form. (Only load h1 tag and other things)
html template
{% load static %}
<div class="box" align="center">
<h1>Write your new password</h1>
<div class="small-line"></div>
<form method="POST">
{% csrf_token %}
{{ context.as_p }}
<button type="submit" class="sendbut">Reset Password</button>
</form>
</div>
forms.py
class SetPasswordForm(forms.Form):
def __init__(self, *args, **kwargs):
super(SetPasswordForm, self).__init__(*args, **kwargs)
# …
new_password1 = forms.CharField(
label=("New password"),
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
strip=False,
help_text=password_validation.password_validators_help_text_html(),
)
new_password2 = forms.CharField(
label=("New password confirmation"),
strip=False,
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
)
views.py
#sensitive_post_parameters()
#never_cache
def PasswordResetConfirmView(request, uidb64=None, token=None,
template_name='users/password_reset_confirm.html',
token_generator=default_token_generator,
set_password_form=SetPasswordForm,
post_reset_redirect=None,
current_app=None, extra_context=None):
"""
View that checks the hash in a password reset link and presents a
form for entering a new password.
"""
UserModel = get_user_model()
assert uidb64 is not None and token is not None # checked by URLconf
if post_reset_redirect is None:
post_reset_redirect = reverse('password_reset_complete')
else:
post_reset_redirect = resolve_url(post_reset_redirect)
try:
# urlsafe_base64_decode() decodes to bytestring on Python 3
uid = force_str(urlsafe_base64_decode(uidb64))
user = UserModel._default_manager.get(pk=uid)
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
user = None
if user is not None and token_generator.check_token(user, token):
validlink = True
title = ('Enter new password')
if request.method == 'POST':
form = set_password_form(user, request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(post_reset_redirect)
else:
form = set_password_form(user)
else:
validlink = False
form = None
title = ('Password reset unsuccessful')
context = {
'form': form,
'title': title,
'validlink': validlink,
}
if extra_context is not None:
context.update(extra_context)
if current_app is not None:
request.current_app = current_app
return TemplateResponse(request, template_name, context)
urls.py
urlpatterns = [
path('password_reset/', views.password_reset, name='password_reset'),
path('password_reset/done/', views.password_reset_done, name="password_reset_done"),
path(r'reset/<uidb64>/<token>/', views.PasswordResetConfirmView, name='password_reset_confirm'),
]
please write {{form.as_p}} insted of {{context.as_p}}
{% load static %}
<div class="box" align="center">
<h1>Write your new password</h1>
<div class="small-line"></div>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="sendbut">Reset Password</button>
</form>
</div>

Django Password Reset Confirm error (custom user model)

I am not that experienced writing Python/Back-end, but trying to improve. In development/localserver I am trying to create a password reset form... but I got the following error when accessing the link from the forgot password email - and before that the password was not saving:
get_context_data() missing 1 required positional argument: 'user'
forms.py (almost copy/paste from Django's form; minor changes)
class ResetPasswordForm(SetPasswordForm):
error_messages = {
'password_mismatch': static_textLanguage['page_user_passwordReset_alert_passwordNotMatch'],
'password_empty': static_textLanguage['global_alert_mandatoryField'],
'minimum_length': static_textLanguage['global_alert_minCharacters_password'],
}
new_password1 = forms.CharField(
required=False,
widget=forms.PasswordInput(attrs={
'id': 'page_userPasswordReset_content_form_input_passwordA',
'maxlength': '25',
'class': 'global_component_input_box'
}),
)
new_password2 = forms.CharField(
required = False,
widget=forms.PasswordInput(attrs={
'id': 'page_userPasswordReset_content_form_input_passwordB',
'maxlength': '25',
'class': 'global_component_input_box'
}),
)
def __init__(self, user, *args, **kwargs):
self.user = user
super(ResetPasswordForm, self).__init__(user, *args, **kwargs)
def clean_new_password1(self):
password1 = self.cleaned_data.get('new_password1')
if password1 == '' or password1 is None:
raise forms.ValidationError(self.error_messages['password_empty'], code='password_field_empty')
elif len(password1) < 8:
raise forms.ValidationError(self.error_messages['minimum_length'], code='password_too_short')
return password1
def clean_new_password2(self):
password1 = self.cleaned_data.get('new_password1')
password2 = self.cleaned_data.get('new_password2')
if password2 == '' or password2 is None:
raise forms.ValidationError(self.error_messages['password_empty'], code='password_field_empty')
if password1 and password2:
if password1 != password2:
raise ValidationError(self.error_messages['password_mismatch'], code='password_mismatch')
password_validation.validate_password(password2, self.user)
return password2
def save(self, commit=True):
password = self.cleaned_data["new_password1"]
self.user.set_password(password)
if commit:
self.user.save()
return self.user
views.py
class UserPasswordResetView(auth_views.PasswordResetConfirmView):
template_name = '../frontend/templates/frontend/templates.user/template.page_passwordReset.html'
form_class = ResetPasswordForm
post_reset_login = True
success_url = reverse_lazy('page_userLoginPrivate')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.user
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.validlink:
context.update({
'validlink': True,
'form': self.form_class(),
'static_json_text': static_textLanguage,
'static_json_textGlobal': static_textGlobal
})
else:
context.update({
'validlink': False,
'form': None,
'title': _('Password reset unsuccessful'),
'static_json_text': static_textLanguage,
'static_json_textGlobal': static_textGlobal
})
return context
template.html (for purpose of this exercise .html was simplified)
<div class="wrapper_page_userPasswordReset">
{% if validlink %}
<form id="page_userPasswordReset_content_form" class="page_userPasswordReset_content_form" method="post" novalidate>
{% csrf_token %}
<div class="global_component_input_box_container">
{{ form.new_password1}}
</div>
<div id="page_userPasswordReset_input_passwordA_alert_errors" class="alert_message_input_danger_format">
{% if form.errors %}
{% for key, value in form.errors.items %}
{% if key == 'new_password1' %}
{{ value }}
{% endif %}
{% endfor %}
{% endif %}
</div>
<div class="global_component_input_box_container">
{{ form.new_password2}}
</div>
<div id="page_userPasswordReset_input_passwordB_alert_errors" class="alert_message_input_danger_format">
{% if form.errors %}
{% for key, value in form.errors.items %}
{% if key == 'new_password1' %}
{{ value }}
{% endif %}
{% endfor %}
{% endif %}
</div>
<button type="submit" id="page_userPasswordReset_content_form_button_submit" class="global_component_button button_background_green">{{ static_json_text.global_button_submit }}</button>
</form>
{% else %}
<button id="page_userPasswordReset_button_forgotPassword" class="global_component_button button_background_green">{{ static_json_text.page_user_passwordReset_notValidLink_button }}</button>
{% endif %}
</div>

Custom registration form. Confirm password

I used custom form for register users. I want do validation for confirm password.
forms.py:
class RegistrationForm(UserCreationForm):
'''Register for new users'''
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = get_user_model()
fields = {'username', 'password1', 'password2', 'email', 'first_name', 'last_name'}
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if commit:
user.save()
return user
template:
<div class="input-group register">
{{ form.password.errors }}
<label for="id_password1">Password: </label>
{{ form.password1 }}
</div>
<div class="input-group register">
{{ form.password.errors }}
<label for="id_password2">Confirm password: </label>
{{ form.password2 }}
</div>
views.py
def registration_view(request):
context = {}
context.update(csrf(request))
context['form'] = RegistrationForm()
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
newuser = auth.authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password2']
)
auth.login(request, newuser)
return redirect('home')
else:
context['form'] = form
return render(request, '/registration.html', context)
How can I add validation for password(also confirm password)?
You inherit from UserCreationForm [GitHub]. This form already does that for you.
Indeed: the clean_password2 will validate that the two passwords are the same:
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
The _post_clean function will validate that the password is a valid password:
def _post_clean(self):
super()._post_clean()
# Validate the password after self.instance is updated with form data
# by super().
password = self.cleaned_data.get('password2')
if password:
try:
password_validation.validate_password(password, self.instance)
except forms.ValidationError as error:
self.add_error('password2', error)
Finally in the save() it will use .set_password() to set the password. This is necessary, since Django's User model will, like any good user model, hash the password.
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
You thus should not interfere with these. You here only want to add first_name and last_name. So you can add that logic with:
class RegistrationForm(UserCreationForm):
'''Register for new users'''
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = get_user_model()
fields = ['username', 'email', 'first_name', 'last_name']
That's all, since the ModelForm will take care of that.
Note that authenticate in your view is probably not necessary, since if you construct a user, it should authenticate. You can just login here:
def registration_view(request):
context = {}
context.update(csrf(request))
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
newuser = form.save()
auth.login(request, newuser)
return redirect('home')
else:
form = RegistrationForm()
context['form'] = form
return render(request, '/registration.html', context)
Try to use this in your register template
<form method="post" id="register-account-form">
{% csrf_token %}
{% for field in form %}
{% if field.help_text %}
<div class="notification error closeable">
<small style="color: grey">{{ field.help_text }}</small>
<a class="close" href="#"></a>
</div>
{% endif %}
{% for error in field.errors %}
<div class="notification error closeable">
<p style="color: red">{{ error }}</p>
<a class="close" href="#"></a>
</div>
{% endfor %}
{% endfor %}
<div class="input-with-icon-left">
<i class="icon-feather-user"></i>
{{ form.username }}
</div>
I find mistake
<div class="input-group register">
{{ form.password1.errors }}
<label for="id_password1">Пароль: </label>
{{ form.password1 }}
</div>
<div class="input-group register">
{{ form.password2.errors }}
<label for="id_password2">Подтвердите пароль: </label>
{{ form.password2 }}
</div>

Hide Django built-in UserCreationForm verifications, and show them when the user fills invalid data

I don't want to display the verifications on the screen neither on username nor on password until a user fills invalid data, how can I do that ?!
Here is my user form in forms.py :
class UserForm(UserCreationForm):
class Meta():
model = User
fields = ('username','first_name','last_name','email','password1','password2',)
def save(self,commit=True):
user = super(UserForm,self).save(commit=False)
user.username = self.cleaned_data["username"]
user.email = self.cleaned_data["email"]
user.first_name = self.cleaned_data["first_name"]
user.last_name = self.cleaned_data["last_name"]
user.password1 = self.cleaned_data["password1"]
user.password2 = self.cleaned_data["password2"]
if commit:
user.save()
return user
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].label = 'Username'
self.fields['first_name'].label = 'First Name'
self.fields['last_name'].label = 'Last Name'
self.fields['email'].label = 'Email Address'
self.fields['password1'].label = 'Password'
self.fields['password2'].label = 'Re-enter Password'
and here is my registration function :
def register(request):
registered = False
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password1)
user.save()
c_user = user_form.instance.id
profile = profile_form.save(commit=False)
profile_form.instance.userid = AuthUser(c_user)
profile.save()
if 'profilepic' in request.FILES:
profile.profilepic = request.FILES['profilepic']
profile.save()
registered = True
else:
print(user_form.errors)
print(profile_form.errors)
else:
user_form = UserForm
profile_form = UserProfileForm
return render(request,'registration/register.html',{'user_form':user_form,'profile_form':profile_form,'registered':registered})
My registration page
My registration template
use this template:
<div class="container">
<div class="col-xs-12 col-sm-8 col-md-4 col-sm-offset-2 col-md-offset-4">
<form method="post">
{% csrf_token %}
<div class="panel panel-default text-center">
<h2>Sign up!</h2>
</div>
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit" class="btn btn-success">Signup!</button>
</form>
</div>
</div>
this will show errors when the user type invalid data.