I am working on a simple site with a login functionality. To handle auth in the backend I am using the Djoser library. I have login functionality working. However now I want to create a site on my frontend which has restricted access based on a users roles.
What I want is that if a users is admin/staff then the frontend site has another page in the navbar. So my question is, how should I go about handling this. My first thought is that, when the user is logging in, then the token is sent to the frontend and stored, and then with the token I would also send the users role and store this aswell. However I am not sure how to extend Djoser to do this.
Another option would be to simply say that after the user has logged in and received the token and stored it in the frontend, I would make a subsequent request to the backend to get that users information including its role and store that aswell. This of course takes 2 backend calls instead of one as in the first option.
To me it seems optimal to use the first option, however I am not sure how to extend the Djoser login path to send both a token and the users role.
Solved it myself, see my answer below to see how I did it.
However if anybody is familiar with a smarter way to achieve what I am trying to, then please post a comment!
Okay, I figured it out myself. Leaving this here if anybody needs it.
First I create a serializer file in my project directory (original app).
Then I took the TokenSerializer from Djoser and extended it to the following,
from rest_framework import serializers
from djoser.conf import settings
class TokenSerializer(serializers.ModelSerializer):
auth_token = serializers.CharField(source="key")
is_staff = serializers.BooleanField(source="user.is_staff", read_only=True, default=False)
class Meta:
model = settings.TOKEN_MODEL
fields = ("auth_token", "is_staff")
I did not realize that you can use the source keyword, with this I can access the user model attached to the token, and the retrieve the is_staff field.
This now makes it so that a user requests a login to /auth/token/login/, with the login details, it responds with a token and whether or not the user has is_staff field set.
Related
Is there a way to set up the django authentication model where, instead of a password, users put in their email address, and then are emailed a link that they click on to login with? If so, are there any tutorials on how to set this up?
Yes, there is.
You'll either need to hope there is already a module out for this, otherwise you will have to write your own way of authenticating.
I'll give a rough estimate of how it's gonna work.
First, you will need to create a class inheriting from AbstractBaseUser
Set the username field to email, still include password fields. They are required.
Then, you will need to create a manager for that custom base user.
the user manager must have two methods: create_user() and create_superuser()
Then, in a view, have user enter their email address, and then generate a token with Django's default_token_generator, and send that token via e-mail to the user.
Create a view which accepts the token, and logs the user in.
I highly advise you to take the docs as your guide. This might get relatively complicated.
More info on the Django Docs
Side note: This will not be as secure as email and password validation. If a user's email gets hacked, the hackers will instantly know not only which site they can target, but also get a free pass to access.
Alternatively; check out Django AllAuth, they provide lots of ways to authenticate, including with Gmail or Facebook. There are some great tutorials online, but you'll have to do some googling. ;)
I want to do a social authentication with Google and Facebook. For that I have use social-auth-app-django. When I login with using Google it will directly create an account in django user model and redirect to my URL. But I want to fill extra required details of user, after entering detail create user after user's confirmation and don't want to directly login new user and redirect to my authenticated page.
Any suggestion is always appreciated.
Thanks.
That's basically the purpose of the partial pipelines feature on python-social-auth (docs). The idea is to pause the authentication flow at any time and resume it later, it's commonly used to ask for more details to the user, or to just send a validation email.
Check the example application here, in the settings it overrides the default pipeline with one that will ask the user for their email address.
I have been asked to introduce an unusual case and I'm wondering how others would go about it.
I have users in my Django application. The model is a standard user model, authentication. etc. Each one of of these site users can add their own contacts to the system. However my new requirement is to allow their contacts to set a password (if they want to to) so that they can login to their status page (belonging to that user).
So my question is how would you do this? I already have the contact table (which belongs to one user), I'm thinking of adding in a password (optional) field, but then I'm unsure how to handle the authentication for this as they are not my users but members of my users (if that make sense).
One way would be to create another user model for contacts inheriting from AbstractBaseUser. And then creating custom auth backend that would look in both models to login user. Finaly you would have to distinguish between standard user and contact user before every action.
That is if contact user and standard user differ significantly in your application.
Or you could just create custom user in your application, that would contain is_contact attribute. This would be used for both types of users. You would set that as AUTH_USER_MODEL in settings and check before every action for the is_contact attribute to determine the outcome. You could return 403 for the contact user if he tries to access what he's not suppose to.
Or if you use permissions in your application, you could set the contact user's persmissions only to view statuses of the users that added him as a contact and nothing else.
I'm trying to figure out how to enhance the authenticate method with additional functionality.
e.g.
Expiring passwords
special password formats
length requirements
etc...
It is pretty straight forward for the site's frontend, but what about the admin panel?
I reckon that I should override the User's Manager object, as authenticate probably resides there. This is quite a tough one to figure out I think.
Thanks in advance! :)
You can create custom authentication backend by following the instructions in http://docs.djangoproject.com/en/dev/topics/auth/#authentication-backends. Essentially, you create a backend class that has an authenticate method:
class MyBackend:
def authenticate(self, username=None, password=None):
# Check the username/password and return a User.
Then add the class to AUTHENTICATION_BACKENDS in settings.py.
Though this is for authentication, you could do all the password validation things you mentioned simply by redirecting a user to a change password page if the password is correct but expired, for instance. Consider using the messaging framework to give a user a hint about what is going on when directing him to a generic change password page.
If you want the validation for passwords to be built into the model, then you'll probably want to extend the django User model.
Otherwise, you could do the following:
override admin password options by creating your own views for changing and setting passwords, then putting the relevant URLS just above (r'^admin/', include(admin.site.urls)). Regex would look something like (r'^admin/auth/user/(\d+)/password/', new_change_password).
Keep track of password age in a separate model and then when they expire, redirect to a change password once it expires.
I don't like models.User, but I like Admin view, and I will keep admin view in my application.
How to overwirte models.User ?
Make it just look like following:
from django.contrib.auth.models import User
class ShugeUser(User)
username = EmailField(uniqute=True, verbose_name='EMail as your
username', ...)
email = CharField(verbose_name='Nickname, ...)
User = ShugeUser
That isn't possible right now. If all you want is to use the email address as the username, you could write a custom auth backend that checks if the email/password combination is correct instead of the username/password combination (here's an example from djangosnippets.org).
If you want more, you'll have to hack up Django pretty badly, or wait until Django better supports subclassing of the User model (according to this conversation on the django-users mailing list, it could happen as soon as Django 1.2, but don't count on it).
The answer above is good and we use it on several sites successfully. I want to also point out though that many times people want to change the User model they are adding more information fields. This can be accommodated with the built in user profile support in the the contrib admin module.
You access the profile by utilizing the get_profile() method of a User object.
Related documentation is available here.