How to hide password in API response? - python

I know that some may say that there is no need to provide password in api-response if i have to hide it. but the point is, even if i go to admin section, i can see the password hash value, that's why i'm doing this.
So my question is, how can I hide that password in my API response. For ex. using asterisks.
Note: I have a custom model for my data.
i just need a function and where to put it to work.
models.py
from django.db import models
from django.contrib.auth.hashers import make_password
class MyUser(models.Model):
full_name = models.CharField(max_length=128)
profile_picture = models.ImageField(upload_to="user_data/profile_picture", blank=True)
username = models.CharField(max_length=128, unique=True)
birth_date = models.DateField(blank=True)
gender = models.CharField(max_length=10, blank=True)
password = models.CharField(max_length=255)
contact = models.CharField(max_length=15, blank=True)
email = models.CharField(max_length=100, unique=True)
time_stamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.username
def save(self, *args, **kwargs):
if not self.pk:
self.password = make_password(self.password)
super(MyUser, self).save()

You can provide any number of asterisks you like, or provide the hashed password (user.password). There is no way for you to know what a user's password is, or how many characters are in it, though, so providing somepassword as ************ (same number of characters) is not possible.
If you feel you need to provide something, I recommend just picking an arbitrary number of asterisks.
As an aside, I would strongly suggest you look at the documentation for extending the Django User model, rather than fully rolling your own.

It's better to override the BaseUserManager, AbstractBaseUser from django.contrib.auth.models to work with your custom model. Thus it will act as a default User model(built-in model) and it will do all. Follow this link to the guide(Code) or Follow this link for step by step brief guide(video tutorial)

Related

How can I do authentication on the site and the built-in Users model and my own Employer Django?

I ran into a problem
I am making a job search site on Django, I have the following logic:
Authorization and authentication of ordinary job seekers using Django's built-in model - User
Also separate authorization and authentication for users who provide work, i.e. employers,
which are placed in my own model Employer
Here is my Employer model
class Employer(AbstractUser):
full_name = models.CharField(max_length=150, verbose_name="Ім'я")
main_office_city = models.ForeignKey(City, on_delete=models.CASCADE,
verbose_name='Місто головного офісу')
phone_number = models.ForeignKey(Phone, on_delete=models.CASCADE)
email = models.CharField(max_length=50, unique=True, verbose_name='Email')
hashed_password = models.CharField(max_length=120, default='')
date_joined = models.DateTimeField(verbose_name='Дата реєстрації',
default=timezone.now)
def __str__(self):
return self.full_name
class Meta:
verbose_name = 'Роботодавець'
verbose_name_plural = 'Роботодавці'
I read in the documentation that to create your own authentication system you can use the imitation from the AbstractUser class
But in my case this is not the best choice, because AbstractModel adds its own fields by default.
That is, I think that I need to either somehow make it so that the AbstractUser class does not add its fields, or think of some other authentication logic using another technology
Maybe someone has some ideas how it can be done?

Django User model with same fields

I saw tutorial on how to extend django model by giving 1-to-1 relationship to the django user model.
My question is, if we have same fields on both User and profile(extend from user) model i.e email and username.
When the user register on our site using User model, does the profile model will inherit the same username and email from User model?
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(
User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, blank=True, null=True)
email = models.EmailField(max_length=500, blank=True, null=True)
location = models.CharField(max_length=200, blank=True, null=True)
When the user register on our site using User the model, does the Profile model will inherit the same username and email from User model?
No, you do not inherit from the user model, you simply create a new model that refers to a user, and it happens to have some fields that are the same. It would also be bad from a software design point-of-view. Imagine that you later add a field to your user model and somehow it is the same as the Profile, then all of a sudden the data should be different?
There is no need to store the data an extra time in the Profile. If you have a Profile object like my_profile, you can access the email address stored in the related user with:
my_profile.user.email
You can also make properties that will obtain it from the user, like:
from django.conf import settings
class Profile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
blank=True
)
location = models.CharField(max_length=200, blank=True, null=True)
#property
def name(self):
if self.user_id is not None:
return self.user.username
#property
def email(self):
if self.user_id is not None:
return self.user.email
Storing the same data is a form of data duplication and often makes software harder to maintain: it means that for every update of the User model, or the Profile model, you will need to synchronize with the other model. This can easily go wrong, resulting in the fact that the Profile can have a different email address than the related User and vice versa, resulting in a lot of problems where one sends emails to the wrong email address, etc.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Is it possible in Django to have 2 different types of users with theirs own login fields in the same app?

I have 2 types of users on my site, one is the store owner, I want to log him in with the usual custom user email and password, the other is the buyer, I want to login the buyer using just a pin number only. Is it possible to have both types of login users in the same django app. Thanks in advance.
class Store(models.Model):
store_name = models.CharField(max_length=200)
store_status = models.BooleanField()
store_details = models.CharField(max_length=300, blank = True)
store_balance = models.IntegerField(default=0)
user = models.OneToOneField(User, on_delete=models.CASCADE)
college = models.ForeignKey(Institute, on_delete=models.CASCADE )
def __str__(self):
return str(self.store_name)+" "+ str(self.store_status)
class Customer(models.Model):
name = models.CharField(max_length=200)
branch = models.CharField(max_length=200, choices=BRANCHES)
sem = models.CharField(max_length=200, choices=SEMESTERS)
reg_no = models.IntegerField(default=0)
balance = models.IntegerField(default=0)
pin_no = models.IntegerField()
college = models.ForeignKey(Institute, on_delete=models.CASCADE )
To make a custom authentication you need to add an Authentication Backend. Firstly your customer model is not related to your user model try adding a OnetoOne field in that. After that try adding code like this in one of your apps:-
from django.contrib.auth.backends import BaseBackend
class MyBackend(BaseBackend):
def authenticate(self, request, token=None):
try:
customer = Customer.objects.get(pin_no=token)
user = customer.user
except Customer.DoesNotExist:
return None
return user
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Refer the documentation on Customizing authentication in Django for more information.
Now after making an AuthenticationBackend you need to make it so that Django uses it, you do this by adding it to AUTHENTICATION_BACKENDS in your settings.py, since you want the default username and password to remain something like this would work:
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend', 'path.to.MyBackend']
You have several ways for this. One is making an index place where they choose the option "owner" or "buyer" and after ask for login auth. Other approach is to make url specifying those options already. If you want to do it in the same "form" you could add specification under the hood for manage this input data provided also could be done by several ways, or make a checkbox like so it changes form input. Choose the one that suits you. Does this help you?

Password field in django admin not displaying value

I have a Crew Model. The table has a password field. I dont want to display password in plain text. So I have added forms where I have used widget=forms.PasswordInput(). But this doesnt display the password after saving the data. How do I display password in hidden format?
class Crew(models.Model):
crew_id = models.AutoField(primary_key=True)
crew_code = models.CharField(max_length=200, null=False, unique=True)
crew_name = models.CharField(max_length=200, null=False)
crew_password = models.CharField(max_length=200, null=False)
Forms.py
class UserForm(forms.ModelForm):
crew_password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = Crew
fields = ('crew_name', 'crew_password', 'crew_code', 'crew_id')
In case you need to safe passwords ( I totally agree this is not the way for django users, but I do have some other connections with passwords saved) you should have a look at django-extensions, using python-keyczar to encrypt passwords).
To answer your question, i aslo found out the password widget does not show whether a password is filled in or empty. (i would expect dots or asterics to show there is something in the field, but should not be shown of course).
this does that exactly:
class SomeConnectionForm(forms.ModelForm):
class Meta:
widgets = {
'password': forms.PasswordInput(render_value = True),
}
the trick is the render_value=True

DRF: Serializer validation while submitting a POST request to detail route

DRF newbie here. I have the following model:
class User(models.Model):
first_name = models.CharField(max_length=30, null=True, blank=True)
last_name = models.CharField(max_length=30, null=True, blank=True)
email = models.EmailField(max_length=254, null=False, blank=False, unique=True)
password = models.CharField(max_length=128, null=False, blank=False)
I've managed to implement POST /users/ successfully. I'm able to validate password and email fields in the request body against pre-defined constraints.(e.g. password cannot be entirely numeric) For this purpose, I override field validators such as validate_password and validate_email.
Now I'm trying to implement an endpoint POST /users/pk/password/ through which users will be able to update their password resource. To achieve this I've used detail_route. Below you can find the corresponding implementation:
# Custom method to update the password resource of a given user.
#detail_route(methods=['post'])
def password(self, request, pk=None):
try:
user = User.objects.get(pk=pk)
except User.DoesNotExist:
# returns error
else:
password = request.data.get('password',None)
new_password = request.data.get('new_password',None)
if password and new_password:
if check_password(password,user.password):
# Use Django built-in to hash password.
password_hash = make_password(new_password)
user.password = password_hash
user.save()
serializer_data = UserSerializer(user).data
return Response(serializer_data)
else:
# return error reponse
else:
# return error response
By using this approach, I'm able to update the password field of a user but validate_password is not effective anymore when POST /users/pk/password/ is called so that users can update their password with an entirely numeric one.
I'm aware of the fact that I can try to implement validate_password inside the detail route implementation, but it does not feel like the best way to go.
My question is what is the best way to do this without duplicating code and without moving validation logic into views.py?
PS: I cannot use nor extend Django User model for various reasons.
Thanks!
This the problem, you are getting the data straight off the raw post, when you are supposed to be using the serializer
password = request.data.get('password',None)
new_password = request.data.get('new_password',None)
Now assuming your serializer with the validation code is called MySerializer, the above lines need to be replaced with something like
serial = MySerializer(data=request.data)
if serial.is_valid():
password = serial.validated_data['password']
new_password = serial.validated_data['new_password']
Now your validation code will be executed.

Categories

Resources