Django same username in different organizations - django

I am building an API with Django rest, and I am dealing with a situation where I have to authenticate users with the same username but in different organizations and I have no idea how to do it, any suggestions ?? I would be grateful.
User model :
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(_('email address'), unique=True)
phone_number = models.CharField(max_length=191, blank=True, null=True)
roles = models.ManyToManyField(to=Role,db_column="nom",blank=True)
objects = CustomUserManager()
multiple_connections = models.BooleanField(default=True)
organization = models.ForeignKey(
to=Organizations,on_delete=models.CASCADE,to_field="organization_key", blank=True, null=True)
def __str__(self):
return self.username
class Meta:
db_table = 'users'
verbose_name_plural = "Users"
unique_together = ('useranme', 'organization',)

Two ways I can think of: you'll need to have users specify their organization as one of the parameters for your authentication API endpoint(s), or provide different authentication API endpoints to users from different organizations.
If you go the first route, you might have everyone POST to /my_api/auth/, and send a payload like:
{
'username': 'Jim123',
'password': 'password123456!',
'organization_id': 7
}
If you go the second route, you would have multiple endpoints like /my_api/organization_a/auth/, my_api/organization_b/auth/, etc.
In both cases, you'll have to have your server-side authentication code make sure it's comparing username/password against users in the correct organization (presumably the organization is stored in your database somewhere).

Related

Prevent concurrent logins django rest framework jwt authentication

I am using djangorestframework-simplejwt==4.4.0 in my application for User Authentication. But by default it provides multiple logins for a single user i.e. I can generate n number of tokens.
What I want is to prevent multiple logins from the same account. How do I do that?
Models.py
class Company(models.Model):
region_coices = (('East', 'East'), ('West', 'West'), ('North', 'North'), ('South', 'South'))
category = (('Automotive', 'Automotive'), ('F.M.C.G.', 'F.M.C.G.'), ('Pharmaceuticals', 'Pharmaceuticals'),
('Ecommerce', 'Ecommerce'), ('Others', 'Others'))
type = models.ManyToManyField(CompanyTypes)
name = models.CharField(max_length=500, default=0)
email = models.EmailField(max_length=50, default=0)
class User(AbstractUser):
is_admin = models.BooleanField(default=False)
company = models.ForeignKey(Company, on_delete=models.CASCADE, blank=True, null=True)
#property
def full_name(self):
return self.first_name + " " + self.last_name
class EmployeeTypes(models.Model):
emp_choices = (('Pool Operator', 'Pool Operator'), ('Consignor', 'Consignor'), ('Consignee', 'Consignee'))
emp_type = models.CharField(max_length=500, default='Pool Operator', choices=emp_choices)
class Employee(models.Model):
role_choices = (('CRUD', 'CRUD'), ('View', 'View'))
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name="company")
name = models.CharField(max_length=500, default=0)
Urls.py
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
You need to implement a login mechanism yourself.
You can store user refresh token with his user agent and IP address in the database or
some cache systems like Redis, when the user wants to refresh the access token, check provided refresh token alongside his IP address and user agent against the database and if any token exists, give him a new access token.
On login, drop unexpired refresh tokens if exist in the database for the user that has a successful login, and then insert the new refresh token you just generated, in the database.
By implementing this solution, if the user tries to log in again, he will be automatically logged out from previous logins.

How to filter a type of user in Django

I am working a particular web application. I have made use of the Django Abstract user has my application has different types of user. I have the admin user as well as the bar owner.
I need to return the number of bar owners in the application but don't know how to go about it.
models.py
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=254, unique=True)
class UserType(models.Model):
is_admin = models.BooleanField(default=False)
is_landlord = models.BooleanField(default=False)
user = models.OneToOneField(User, on_delete=models.CASCADE)
Note: I need to be able to return the number of is_landlord
For returning the no. of users who are landords you can use the query
UserType.objects.filter(is_landlord=True).count()

How to have two type of users with different logins using Django?

I have two type of Users Artist and Customer. so far I have this
in models.py
class User(AbstractBaseUser, PermissionsMixin):
Email = models.EmailField(unique=True)
USERNAME_FIELD = 'Email'
objects = MyUserManager()
class Customers(models.Model):
User = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
CustomerID = models.AutoField(primary_key=True)
class Artists(models.Model):
User = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
ArtistID = models.AutoField(primary_key=True)
I use Email as authentication, and it is good until an Artist wants to be Customer too.
and he/she can't have two accounts one as Customer and another as Artist with the same Email.
here my questions:
Is this way of implementation correct? if not, how to do that?
what is the best way to have a user be Artist and Customer at the same time? Is this have security issues?
I've found that it's usually a bad idea to derive subclasses from Users.
Instead, use a custom user model and add flags for the various roles (and yes, I'm deriving from AbstractUser on purpose; many apps expect .username to be a thing, and you can just always assume username == email):
class User(AbstractUser, PermissionsMixin):
is_customer = models.BooleanField(default=False)
is_artist = models.BooleanField(default=False)
I also suggest looking into an app like django-allauth (which will work with custom user models) to make the whole register/login/password-change/email-confirmation flows easier.
I changed my models a bit and create a OneToOne relation between Artist and Customer:
class User(AbstractBaseUser, PermissionsMixin):
Email = models.EmailField(unique=True)
USERNAME_FIELD = 'Email'
objects = MyUserManager()
class Customers(models.Model):
User = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
CustomerID = models.AutoField(primary_key=True)
class Artists(models.Model):
Customer = models.OneToOneField(Customers, on_delete=models.CASCADE)
ArtistID = models.AutoField(primary_key=True)

Django update model without UpdateView

I have a scenario where in my users profile they have an associated organisation. I need to be able to allow the users to select and set this organisation (user_organization), however I would like to do it without allowing them to just see a list (drop down menu) of all the organisations within the application. My work around for this was to issue each organisation with a unique code (org_code) and allow users to enter that code into a form and have the related organisation applied to their profile. I can easily understand the suedocode logic behind this, however I am unsure how to implement it within my views and forms. If anyone can advise me the best way to do this or point me in the correct direction to learn how? It would be appreciated. See my models below for clarification on how things fit together.
Profile:
class Profile(models.Model):
Super_Admin = "Super_Admin"
Admin = "Admin"
Manager = "Manager"
Developer = "Developer"
ROLE_CHOICES = (
(Super_Admin, 'Super_Admin'),
(Admin, 'Admin'),
(Manager, 'Manager'),
(Developer, 'Developer'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
user_group = models.OneToOneField(Group, on_delete=models.CASCADE, blank=True, null=True)
user_organization = models.OneToOneField(Organization, on_delete=models.CASCADE, blank=True, null=True)
role = models.CharField(choices=ROLE_CHOICES, default="Developer", max_length=12)
activation_key = models.CharField(max_length=120, blank=True, null=True)
activated = models.BooleanField(default=False)
def __str__(self):
return self.user.username
Organizations:
class Organization(models.Model):
org_name = models.CharField(max_length=120, blank=False, unique=True)
org_code = models.CharField(max_length=120, blank=False, unique=True, default=GenerateOrganozationCode)
Answering using the extra info from the comments you've made above:
"I want them to be able to input a code into a text field which when submitted, if it matches the code (org_code) in the organization model it will then populate the (user_organization) in their Profile with the correct (org_name)"
Within the logic for the view, you need to extract the org_code. You should also make org_code of Organization the primary key of the object (you dont have to, but it would be easier if the pk was the org code). From here, you can map the org_code with the primary key value of Organization.
Organization.objects.get(pk=the_entered_org_code)
If you'd rather not assign org code as the primary key of the object, you can just filter for the org code.
Organization.objects.filter(org_code=the_entered_org_code)
This should get you started.

Non-user base TokenAuthentication for django-rest-framework

I'm trying to create an api with token authentiaction. My problem is that I don't want tokens to be associated with user accounts but rather an account model.
For example:
class Account(models.Model):
slug = models.SlugField()
name = models.CharField(max_length=255)
website = models.URLField(blank=True, default='')
members = models.ManyToManyField(User, through='AccountMember')
class AccountMember(models.Model):
ADMIN = 1
MANAGER = 2
MEMBER = 3
ROLES = (
(ADMIN, 'administrator'),
(MANAGER, 'manager'),
(MEMBER, 'member'),
)
user = models.ForeignKey(User)
account = models.ForeignKey(Account)
role = models.PositiveSmallIntegerField(choices=ROLES)
date_joined = models.DateField(auto_now_add=True)
class Token(models.Model):
"""
The default authorization token model.
"""
key = models.CharField(max_length=40, primary_key=True)
account = models.ForeignKey(Account, related_name='auth_tokens')
only_allowed_ips = models.BooleanField(default=False)
ip_list = models.TextField(default='', blank=True)
created = models.DateTimeField(auto_now_add=True)
As you can see, there are multiple users associated with an account so assigning the token to them would be useless.
I also want to be able to add multiple tokens to an account.
Does anyone know the best way I could add authentication/permissions to a system like this?
You must replicate the following classes:
django.contrib.auth.backends.ModelBackend: to check for auth and permissions
django.contrib.auth.middleware.AuthenticationMiddleware: to set your Account linked with the request
probably you must create another django.contrib.auth.models.Permission to store your Account related permissions
I just faced the problem myself. What I decided to do is too duplicate django rest framework's authtoken module in my application and to apply my own modifications.
You can copy the folder from DRF's repository in your own application's folder. Be sure to change related fields in your settings.py, application/authtoken/admin.py and of course in your application/authtoken/models.py