1

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() function.

class CustomAuthBackend(ModelBackend):

def authenticate(self, request, username=None, password=None, **kwargs):
    user = CustomUser.objects.using(request.POST['kundennr']).get(username=username)
    if user.check_password(password) and self.user_can_authenticate(user) :
         try:
            user = CustomUser.objects.using(request.POST['kundennr']).get(username=username)
            return user
         except User.DoesNotExist:
            return None

def get_user(self, user_id):
    try:
        return CustomUser.objects.get(pk=user_id)
    except User.DoesNotExist:
        return None

The authentication function works fine that way the problem i have is the get_user function i guess because the get_user function has no request where i can define which database it should call on. because everytime i call {% if user.is_authenticated %} it goes to the default database and says user is Anonymous. I dont know the right way to solve this problem is my solution just wrong?

  • What you want is fairly complicated and your solution won't work. Look at [this post](https://stackoverflow.com/questions/21771345/multi-tenant-saas-in-django) or google for "django multi-tenant" – dirkgroten Nov 21 '18 at 12:50
  • Or look at [this book](https://books.agiliq.com/projects/django-multi-tenant/en/latest/index.html) – dirkgroten Nov 21 '18 at 12:56

1 Answers1

1

okay after trying some stuff i got a solution which i think works for the first step but i dont know if there are security problems or any other errors if i use it like this

from app.models import CustomUser
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import login as auth_login
from app.middleware import ThreadLocal

class CustomAuthBackend(ModelBackend):

def authenticate(self, request, username=None, password=None, **kwargs):
    user = CustomUser.objects.using(request.POST['kundennr']).get(username=username)
    if user.check_password(password) and self.user_can_authenticate(user) :
         try:
            user = CustomUser.objects.using(request.POST['kundennr']).get(username=username)
            request.session['kundennr']=request.POST['kundennr']
            return user
         except User.DoesNotExist:
            return None

def get_user(self, user_id):
    try:
        request = ThreadLocal.get_current_request()
        return CustomUser.objects.using(request.session['kundennr']).get(pk=user_id)
    except User.DoesNotExist:
        return None

i imported a ThreadLocal.py into middleware so i can get the request object in get_user and when i login i save the customer into a session variable which i call in get_user then is this solution acceptable or are there some risks?

  • The problem with this approach is that for every object you want to fetch (not just `User`) you have to add the `using()` with the correct database. This becomes quite unmanageable. Also note that you're fetching the `user` in the first line of `authenticate` (without try .. except) and then fetching the same `user` again. – dirkgroten Nov 21 '18 at 13:11
  • How are you going to create the new databases each time you get a new customer and register the database with Django (so that you can actually do `using()`)? – dirkgroten Nov 21 '18 at 13:14
  • i use mssql and got a script to create new database for a customer so i need to edit the settings.py for every new customer i guess and ye i have to use using() all the time but for me its not about if its a solution thats not beautiful i just want to know if it works this way or are there any risks in errors or security. ye i need to make a try block the first time i fetch the user in authenticate but when i have a session variable who saves the customernumber i just can copy `using(request.session['kundennr'])` every time i got a database access right? – Le-Hao Nguyen Nov 21 '18 at 13:22
  • What session backend are you using? Cookies or database? – dirkgroten Nov 21 '18 at 13:43
  • Im using database sessions – Le-Hao Nguyen Nov 21 '18 at 13:51
  • 1
    Then I guess in terms of security I don't see how a user could manipulate the session data, so this seems safe to me, as long as you: only allow requests over https (for your entire site) and make sure you have SESSION_COOKIE_SECURE set to True in your settings. – dirkgroten Nov 21 '18 at 14:33