I've made a user model with USERNAME_FIELD defined as phone_number. So login form requires phone_number and password. I want users to be able to also login through their emails. So I created an authentication backend class. Users can login with their phone numbers but they canbot do so with their emails and will receive the 'Username and/or password is wrong' message.
authentication.py:
from django.contrib.auth import get_user_model
class CustomAuthBackend:
def authenticate(self, username=None, password=None):
try:
user = get_user_model().objects.get(email=username)
if password:
if user.check_password(password):
return user
return None
except:
return None
def get_user(self, user_id):
try:
user = get_user_model().objects.get(pk=user_id)
return user
except:
return None
forms.py:
class UserLoginForm(forms.Form):
username = forms.CharField(label="Phone Number / Email")
password = forms.CharField(widget=forms.PasswordInput(), label="Password")
views.py:
class UserLogin(View):
form_class = UserLoginForm
template_name = "accounts/login.html"
def get(self, request):
return render(request, self.template_name, {"form": self.form_class})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
cd = form.cleaned_data
user = authenticate(
request, username=cd["username"], password=cd["password"]
)
if user:
login(request, user)
messages.success(request, "Logged in successfully.", "success")
return redirect("home:home")
else:
messages.error(request, "Username and/or password is wrong.", "danger")
return render(request, self.template_name, {"form": form})
messages.error(request, "Login failed", "danger")
return render(request, self.template_name, {"form": form})
settings.py:
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"accounts.authentication.CustomAuthBackend",
]
Assuming that you have already included the custom backend in AUTHENTICATION_BACKENDS setting in settings.py file.
You can make a condition check that whether it is a phone no. or email using regex so:
import re
from django.contrib.auth import get_user_model
class CustomAuthBackend:
def authenticate(self, request, username=None, password=None):
UserModel = get_user_model()
# Check whether username is an email address or phone number
if re.match(r'^\+?\d{10,14}$', username):
try:
user = UserModel.objects.get(phone_number=username)
if user.check_password(password):
return user
except UserModel.DoesNotExist:
return None
else:
try:
user = UserModel.objects.get(email=username)
if user.check_password(password):
return user
except UserModel.DoesNotExist:
return None
def get_user(self, user_id):
try:
return get_user_model().objects.get(pk=user_id)
except get_user_model().DoesNotExist:
return None
I had forgotten to include request as a parameter in authenticate method. :)
Correct version:
def authenticate(self, request, username=None, password=None):
# ...
Related
Why when i desactive user on Django admin site in my class in post method
requirement return negative first if requirement user is not None ?
Probably if user desative true Django don`t look him in user table ?
class LoginView(View):
template_name = 'login.html'
def get(self, request):
form = LoginForm()
return render(request, self.template_name, locals())
def post(self, request):
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('home')
else:
alert = messages.error(request, 'Twoje konto zostało zablokowane!')
return render(request, self.template_name, locals())
else:
alert = messages.error(request, 'Błędna nazwa użytkownika!')
return render(request, self.template_name, locals())
In authenticate function, django call authenticate on your AUTHENTICATION_BACKENDS in settings.py.
ModelBackend is a default authentication backend that has been provided by Django, and if you are using it, it checks if user is acive or not. It's sth like this:
def user_can_authenticate(self, user):
"""
Reject users with is_active=False. Custom user models that don't have
that attribute are allowed.
"""
is_active = getattr(user, 'is_active', None)
return is_active or is_active is None
How can I authenticate and login the user from Active Directory? This is my code
Authenticate.py:
from .models import User
from ldap3 import ALL, Server, Connection, NTLM
from ldap3.core.exceptions import LDAPException
from django.contrib.auth.backends import ModelBackend
def validate_user_credentials(username, password):
server = Server(host='#xxxDomain',
use_ssl=False, get_info=ALL)
try:
with Connection(
server, authentication="NTLM", user=f"{''}\\{username}", password=password, raise_exceptions=False,
) as connection:
print(connection.result['description'])
return True
except LDAPException as e:
print(e)
return False
class UserAuth(ModelBackend):
def authenticate(self,request,username=None,password=None,**kwargs):
try:
if (validate_user_credentials(username, password)):
print("Helloooooooooooooo")
user = User.objects.get(username=username)
print(user)
return user
return None
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(username=user_id)
except User.DoesNotExist:
return None
views.py:
class UserLoginView(View):
form_class = UserLoginForm
def get(self, request):
form = self.form_class
return render(request, 'login/login.html', {'form': form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
cd = form.cleaned_data
userexistindb = User.objects.filter(
username=cd['username'], is_user_local=False).exists()
username = cd['username']
password = cd['password']
try:
if userexistindb:
try:
user = authenticate(
request, username=username, password=password)
if (user is not None):
login(request=request, user=user)
messages.success(
request, 'Loged in success', 'success')
return redirect('login:result')
else:
messages.error(request, 'us', 'warning')
except User.DoesNotExist:
messages.error(
request, 'Invalid User/Password', 'warning')
except User.DoesNotExist:
username = None
messages.error(
request, 'Invalid User/Password', 'warning')
return render(request, 'login/login.html', {'form': form})
The result is the sessionid It is created,The username and password
are correct and the answer is correct
but the captured user information is not displayed. Information is
displayed in the log!
enter image description here
What should I do!
I am new to django and I wanted to authenticate user on email or username with password hence I wrote a custom authentication as shown in documentation but it doesn't seem to be called and I have no idea what do I do?
settings.py
AUTHENTICATION_BACKENDS = ('accounts.backend.AuthBackend',)
views.py
def login(request):
if request.method == 'POST':
username_or_email = request.POST['username']
password = request.POST['password']
user = authenticate(username=username_or_email, password=password)
print(user)
if user is not None:
return reverse('task:home')
else:
messages.error(request, "Username or password is invalid")
return render(request, 'accounts/login.html')
else:
return render(request, 'accounts/login.html')
backend.py
from django.contrib.auth.models import User
from django.db.models import Q
class AuthBackend(object):
supports_object_permissions = True
supports_anonymous_user = False
supports_inactive_user = False
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
def authenticate(self, username, password):
print('inside custom auth')
try:
user = User.objects.get(
Q(username=username) | Q(email=username) )
print(user)
except User.DoesNotExist:
return None
print(user)
if user.check_password(password):
return user
else:
return None
I wrote this print statements in my class to check if they are being called and being written in console. However, they are not being printed and the print statement in views.py prints None
You need to extend the ModelBackend from django.contrib.auth.backends
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
User = get_user_model()
class AuthBackend(ModelBackend):
supports_object_permissions = True
supports_anonymous_user = False
supports_inactive_user = False
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
def authenticate(self, request, username=None, password=None):
print('inside custom auth')
try:
user = User.objects.get(
Q(username=username) | Q(email=username) )
print(user)
except User.DoesNotExist:
return None
print(user)
if user.check_password(password):
return user
else:
return None
And also in settings.py don't forget to add your custom backend authentication
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'accounts.backend.AuthBackend'
]
Another Possible Solution
From you code what I am seeing is that you want your email should treat as user_name of User model. You can easily modify Django's AbstructUser model like following
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
# your necessary additional fields
USERNAME_FIELD = 'email' # add this line
Now email field will treat as an user_name field. No need to add custom authentication-backend
import sys
from django.contrib.auth import get_user_model
from accounts.models import Token
User = get_user_model()
class PasswordlessAuthenticationBackend:
def authenticate(self, uid=None):
print('uuuuuuuuu')
print('uid', uid, file=sys.stderr)
if not Token.objects.filter(uid=uid).exists():
print('no token found', file=sys.stderr)
return None
token = Token.objects.get(uid=uid)
print('got token', file=sys.stderr)
try:
user = User.objects.get(email=token.email)
print('got user', file=sys.stderr)
return user
except User.DoesNotExist:
print('new user', file=sys.stderr)
return User.objects.create(email=token.email)
def get_user(self, email):
try:
return User.objects.get(email=email)
except User.DoesNotExist:
return None
I have a custom user model. After doing successful login, I am getting the anonymous user in HttpResponseRedirect and templates as well. How do I get the logged in user?
Login View:
class LoginFormView(View):
form_class = UserLoginForm
user_model = get_user_model()
template_name = 'account/login.html'
def get(self, request, *args, **kwargs):
form = self.form_class
return render(request, self.template_name, {'form':form})
def post(self, request, *args, **kwargs):
email = request.POST['email']
password = request.POST['password']
user = authenticate(email=email, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect(reverse('home'))
else:
messages.error(request, 'Please enter correct email and password!')
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
If you have the request template context processor enabled, you'll be able to access the user in the template with {{ request.user}}.
Secondly, make sure you are importing the login function and not the login view. It should be:
from django.contrib.auth import login
The django usermodel django.contrib.auth.models.User has a field 'last_login' record the time when a user is successfully login.
But I donot see a code such as 'last_login=datetime.now()' in function from django.contrib.auth import login or from django.contrib.auth import authenticate. I also checked the django.contrib.auth.signals.user_logged_in.
where is the code for update the field 'last_login'?
Below is all the related source coede,how is the login process invoke the update_last_login? I don't see any code in login views or Authenticate function suoure code.
def update_last_login(sender, user, **kwargs):
"""
A signal receiver which updates the last_login date for
the user logging in.
"""
user.last_login = timezone.now()
user.save(update_fields=['last_login'])
user_logged_in.connect(update_last_login)
from django.dispatch import Signal
user_logged_in = Signal(providing_args=['request', 'user'])
#sensitive_post_parameters()
#csrf_protect
#never_cache
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.REQUEST.get(redirect_field_name, '')
if request.method == "POST":
form = authentication_form(request, data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security check complete. Log the user in.
auth_login(request, form.get_user())
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
current_site = get_current_site(request)
context = {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)
class ModelBackend(object):
"""
Authenticates against settings.AUTH_USER_MODEL.
"""
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
if user.check_password(password):
return user
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
UserModel().set_password(password)
user_logged_in signal is connected to django.contrib.auth.models.update_last_login function, it makes:
user.last_login = timezone.now()
user.save(update_fields=['last_login'])
I think the best way of doing this thing is
request_user, data = requests.get_parameters(request)
user = requests.get_user_by_username(data['username'])
update_last_login(None, user)
You can also get user for request object by doing following.
user = request.user
on djnago 1.11
add this class :
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
if request.user and request.user.is_authenticated:
user = request.user
user.last_login = timezone.now()
user.save(update_fields=['last_login'])
return request.user and request.user.is_authenticated
on setting file change :
'DEFAULT_PERMISSION_CLASSES': (
# custom class
'IsAuthenticated',
),