Django Authentication on different databases - django

I want to create an App for Customers where every customer has its own DB. So as Login information they need to enter three different fields: customernumber, username, password.
The username and password should do the normal authentication stuff and the customernumber is there to go to the right database user table for authentication i can go to other databases through the using() method but how do you authenticate a user through the right database?

You should write custom authentication backend like below and it must be specified on settings.py using AUTHENTICATION_BACKENDS key. Django doc
from django.contrib.auth.backends import ModelBackend
class CustomAuthBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
user = User.objects.using(request.GET['CUSTOMER_TABLE']).filter(username=username)
if user.check_password(password) and self.user_can_authenticate(user):
return user

Related

Django Authentication to use both email and username

I've been nearly done with my django-react app with all the models, serializers, and APIs. But now I need to change the authentication method to also use email.
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(unique=True)
# Notice there is no username field, because it is included in AbstractUser
I've looked through some possible solutions but they involve using AbstractBaseUser while some other write a custom authentication backend that omits the username completely. This might break other views and frontend since we have been mainly using username.
I still want to keep the username and use both username and email to authenticate.
Is there any simple idea (preferably kept using AbstractUser) that I wouldn't have to make major change?
This code is taken from the book “Django 3 by Example”, chapter 4, section “Building a custom authentication backend”.
Django provides a simple way to define your own authentication backends. An authentication backend is a class that provides the following two methods: authenticate() and get_user().
Suppose you have the account app in your project to manage the authentication logic. You can create the authentication.py file with the following code:
class EmailAuthBackend(object):
"""
Authenticate using an e-mail address.
"""
def authenticate(self, request, username=None, password=None):
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
return None
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
The preceding code works as follows:
authenticate(): You try to retrieve a user with the given email address and check the password using the built-in check_password() method of the user model. This method handles the password hashing to compare the given password with the password stored in the database.
get_user(): You get a user through the ID provided in the user_id parameter. Django uses the backend that authenticated the user to retrieve the User object for the duration of the user session.
Edit the settings.py file of your project and add the following setting:
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'account.authentication.EmailAuthBackend',
]
In the preceding setting, you keep the default ModelBackend that is used to authenticate with the username and password and include your own email-based authentication backend.
Django will try to authenticate the user against each of the backends, so now you should be able to log in seamlessly using your username or email account. User credentials will be checked using the ModelBackend authentication backend, and if no user is returned, the credentials will be checked using your custom EmailAuthBackend backend.

Access Django Admin with token instead of password

I use Django with Django Rest Framework as the backend for my site. Registration is disabled, and login with password is disabled. The only way a user can register and login is with Django Social Auth, that exchanges (in this case Discord) a social token for a Django token, and in that process the user is created if they don't exist for that email.
So in Django, the user exists, with a username and email, but they don't have a password.
How can these users login to the admin panel?
Registration is disabled, and login with password is disabled.
Registration is not the only way of creating users. You can create superuser using createsuperuser shell command. Then you can use it to login into admin site.
Now, the question is if you want to allow all users to admin site. IMHO, you should not. Still, if you want to then you can add a custom auth backend, like this:
class CustomBackend(BaseBackend):
def authenticate(self, request, username=None, password=None):
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return None
check_token = Token.objects.filter(user=user, token=token).exists()
if check_token:
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
And add the new backend in settings.py:
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend', 'path.to.CustomBackend']

Login Page without Bultin Login System Django

I have a model called Van that have 2 fields: Plate and Password. I should use this informations to login in a frontend system (not django admin).
Searching on the internet i just found example using Bultin Login System but i need a custom login using only Van model.
Any suggestions?
You need to implement custom authorization backend.
For example you can modify this:
from django.contrib.auth.backends import ModelBackend
class EmailAuthBackend(ModelBackend):
def authenticate(self, username=None, password=None, **kwargs):
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
except ObjectDoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
User().set_password(password)

Django allauth with email as username and multiple sites

Is it possible to use Django allauth with the authentication method set to 'email' when using it on multiple sites?
I'm aiming to allow a user with the email address bob#example.com to create an account at site1.com and a separate account at site2.com.
In order to use email authentication, I need to leave UNIQUE_EMAIL set to True in the settings but this prevents users who already have accounts in one site from creating accounts in the other site.
I am assuming you'd like to allow the same email to be registered separately for each of the sites in your Django setup.
Looking at the allauth code; it appears that it is infeasible to do so at the moment, likely because allauth does not take into account site ID as part of the User signup process.
class AppSettings(object):
class AuthenticationMethod:
USERNAME = 'username'
EMAIL = 'email'
USERNAME_EMAIL = 'username_email'
class EmailVerificationMethod:
# After signing up, keep the user account inactive until the email
# address is verified
MANDATORY = 'mandatory'
# Allow login with unverified e-mail (e-mail verification is
# still sent)
OPTIONAL = 'optional'
# Don't send e-mail verification mails during signup
NONE = 'none'
def __init__(self, prefix):
self.prefix = prefix
# If login is by email, email must be required
assert (not self.AUTHENTICATION_METHOD ==
self.AuthenticationMethod.EMAIL) or self.EMAIL_REQUIRED
# If login includes email, login must be unique
assert (self.AUTHENTICATION_METHOD ==
self.AuthenticationMethod.USERNAME) or self.UNIQUE_EMAIL
One way to do this would be as follows:
- Keep allauth AUTHENTICATION_METHOD as Username
- Store the site alongside the User information, perhaps in a UserProfile or by overriding the User Model.
- Make the combination of Email and Site unique.
- Override the LoginView such that the user enters email; you can translate the combination of Email, Site to a Unique User account and username; which you can pass on to allauth to perform login.
Assuming you use the Sites framework; your code would look something like this:
from allauth.account.views import LoginView
from django.core.exceptions import ObjectDoesNotExist
class CustomLoginView(LoginView):
def get_user():
email = request.POST.get('email')
current_site = Site.objects.get_current()
try:
user = User.objects.get(email=email, site=current_site)
except ObjectDoesNotExist:
pass # Handle Error: Perhaps redirect to signup
return user
def dispatch(self, request, *args, **kwargs):
user = self.get_user()
request.POST = request.POST.copy()
request.POST['username'] = user.username
return super(CustomLoginView, self).dispatch(request, *args, **kwargs)
Then monkey-patch the LoginView with the custom login view:
allauth.account.views.LoginView = CustomLoginView
Related Reading on setting up a Site FK, and custom auth backends:
How to get unique users across multiple Django sites powered by the "sites" framework?
https://docs.djangoproject.com/en/dev/topics/auth/#writing-an-authentication-backend

Custom Authentication Backend in Django

How to write a custom authentication backend in Django taking scenario as Phone Number & OTP(One-Time Password) to authenticate against each user.
How to authenticate each user in form of multiple conditions.
If email is verified and password exist ( authenticate using email and password).
If phone is verified and exist( authenticate using phone and otp or if password exist then auth using phone and password).
from django.contrib.auth import backends, get_user_model
from django.db.models import Q
class AuthenticationBackend(backends.ModelBackend):
"""
Custom authentication Backend for login using email,phone,username
with password
"""
def authenticate(self, username=None, password=None, **kwargs):
usermodel = get_user_model()
try:
user = usermodel.objects.get(
Q(username__iexact=username) | Q(email__iexact=username) | Q(phone__iexact=username)
if user.check_password(password):
return user
except usermodel.DoesNotExist:
pass
For you have to specify the authclass in settings.py
AUTHENTICATION_BACKENDS = (
'applications.accounts.auth_backends.AuthenticationBackend',
)
There are many ways to extend user model, here I leave you this page and you can choose which of them is better for you https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html