'User' Object has no attribude is_authenticated - django

I've created a User model for my django app
class User(Model):
"""
The Authentication model. This contains the user type. Both Customer and
Business models refer back to this model.
"""
email = EmailField(unique=True)
name = CharField(max_length=50)
passwd = CharField(max_length=76)
user_type = CharField(max_length=10, choices=USER_TYPES)
created_on = DateTimeField(auto_now_add=True)
last_login = DateTimeField(auto_now=True)
def __unicode__(self):
return self.email
def save(self, *args, **kw):
# If this is a new account then encrypt the password.
# Lets not re-encrypt it everytime we save.
if not self.created_on:
self.passwd = sha256_crypt.encrypt(self.passwd)
super(User, self).save(*args, **kw)
I've also created an authentication middleware to use this model.
from accounts.models import User
from passlib.hash import sha256_crypt
class WaitformeAuthBackend(object):
"""
Authentication backend fo waitforme
"""
def authenticate(self, email=None, password=None):
print 'authenticating : ', email
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
user = None
if user and sha256_crypt.verify(password, user.passwd):
return user
else:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
I have ammended the settings.py file correctly and if I add some print statements to this backend I can see the user details print out. I don't recall reading that I need to implement is_authenticated in the django docs. Am I missing something silly?

I'm not quite sure why you have created a new User model instead of using Django's built-in one and adding a linked UserProfile, which is the recommended thing to do (until 1.5 is released, when pluggable user models will be available). However, yes you need to define an is_authenticated method, which always returns True: this is exactly what the built-in model does. The reason is that if you have an actual User, it will always be authenticated: otherwise, you will have an AnonymousUser object, whose is_authenticated method always returns False.

you dont have to reinvent the wheel. Just use Djangos build in authentication system and save yourself a lot of trouble. You can also extend it to your needs or use different authentication backends. Have a read here. HTH.

Related

Implement djangorestframework-simplejwt token authentication without password

My app does not require password as I want to login with phone and OTP.
I'm trying to implement custom simple JWT token authentication which takes only a phone number and no passwords.
I'm new to Django and I did check some links in stackoverflow and tried this:
class CustomSerializer(TokenObtainPairSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields[self.username_field] = serializers.CharField()
del self.fields['password']
def validate(self,attr):
print(attr)
data = super().validate(attr)
token = self.get_token(self.user)
print (token)
try:
request = self.context["request"]
print(request)
except KeyError:
pass
request_data = json.loads(request.body)
print(request_data)
So here when validate method is executed, it goes to validate TokenObtainPairSerializer init method which in return calls init method of it's parent class which is validating the password.
So even if I'm deleting password field in my custom serializer, it still gives me a key-error of password.
I tried to pass the key-error but again it gets failed at request.body.
I'm stuck on this and I don't know how to implement simple JWT without password.
I had the same question and after a lot of searching and reading the source code of django-rest-framework-simplejwt I got an answer.
So even if i am deleting passowrd field in my custom serializer, it still give me key-error of password
If you take a look at the TokenObtainSerializer class, which is the parent Serializer of TokenObtainPairSerializer here, you can see that the password is called like this:
# rest_framework_simplejwt/serializers.py
def validate(self, attrs):
authenticate_kwargs = {
self.username_field: attrs[self.username_field],
'password': attrs['password'],
}
# ...
So even though you delete the password field, it is still called later on.
What I did was setting the password field as not required and assigning an empty string as password.
class TokenObtainPairWithoutPasswordSerializer(TokenObtainPairSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['password'].required = False
def validate(self, attrs):
attrs.update({'password': ''})
return super(TokenObtainPairWithoutPasswordSerializer, self).validate(attrs)
Now it is possible to use this Serializer in a View.
class TokenObtainPairWithoutPasswordView(TokenViewBase):
serializer_class = TokenObtainPairWithoutPasswordSerializer
Then I created a custom authentication backend so that the user can authenticate without a password.
from django.contrib.auth.backends import BaseBackend
class AuthenticationWithoutPassword(BaseBackend):
def authenticate(self, request, username=None):
if username is None:
username = request.data.get('username', '')
try:
return User.objects.get(username=username)
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
You can read the docs for more information on creating your custom authentication backend.
Finally, on settings.py change your AUTHENTICATION_BACKENDS variable.
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'core.custom_authentication.AuthenticationWithoutPassword',
)
Now Django will try to authenticate using the first authentication ModelBackend and then the new AuthenticationWithoutPassword.
Just saying the obvious here, but keep in mind that authentication without password is definitely not safe, so you should add more logic to your custom authentication, remember that you can access the request variable.

django edit user and userprofile object

so i'm making a generic "accounts" page in django. I've used the django-registration plugin, and currently have a (djang-standard) User object, as well as a UserProfile and UserProfileForm object.
This is a question of style, or best-practices, i suppose. Is what i'm planning "right" or is there a "better/recommended/standard way" to do this?
What i'm planning on doing is creating the UserProfile from the request.user ie:
form = UserProfileForm(instance=User)
(and sending that form to the view), and in the UserProfileForm:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
def __init__(self,*args,**kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
if kwargs.has_key('instance'):
self.user = kwargs['instance']
where my UserProfile is pretty much like so:
class UserProfile(models.Model):
user = models.OneToOneField(User)
points = models.IntegerField(default=0) #how is the user going with scores?
and where User is of the django.contrib.auth.models variety.
Ok! The handling of the editing and saving will either be done via the mixin django stuff or, more likely because i haven't read up on mixins my own user-defined view that handles post and gets. But ignoring that - because i'm sure i should be using the mixins - is the above "right?" or are there suggestions?
cheers!
Take a look at user profiles on the django docs, the basics are listed there. You should also take a look at using a form in a view.
Some specific feedback:
You got the UserProfile model right, but you have to create an instance of one every time a new user is added (either through the admin interface or programmatically in one of your views). You do this by registering to the User post_save signal:
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
You should init the ModelForm with an instance of the UserProfile, not User. You can always get the current user profile with request.user.get_profile() (if you define AUTH_PROFILE_MODULE in settings.py). Your view might look something like this:
def editprofile(request):
user_profile = request.user.get_profile()
if request.method == 'POST':
form = UserProfileForm(request.POST, instance=user_profile)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/profile')
else:
form = UserProfileForm(instance=user_profile)
# ...
No need for the init override in your ModelForm. You will be calling it with a UserProfile instance, anyway. If you want to create a new user, just call the User constructor:
user = User()
user.save()
form = UserProfileForm(instance = user.get_profile())
# ...

Using email as username with django

I have run into the following error trying to create a user in django:
>>> email = 'verylongemail#verylongemail.com'
>>> user_object = User.objects.create_user(username=email, email=email, password='password')
Data truncated for column 'username' at row 1
It seems Django has a limit on the number of chars allowed in a username. How would I get around this?
I've had to modify the auth_user table by hand to make the field longer and then convert emails into a username by removing the # symbol and the period (maybe other characters too, it's really not a great solution). Then, you have to write a custom auth backend that authenticates a user based on their email, not the username, since you just need to store the username to appease django.
In other words, don't use the username field for auth anymore, use the email field and just store the username as a version of the email to make Django happy.
Their official response on this topic is that many sites prefer usernames for auth. It really depends if you are making a social site or just a private site for users.
If you override the form for Django users you can actually pull this off pretty gracefully.
class CustomUserCreationForm(UserCreationForm):
"""
The form that handles our custom user creation
Currently this is only used by the admin, but it
would make sense to allow users to register on their own later
"""
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = User
fields = ('first_name','last_name','email')
and then in your backends.py you could put
class EmailAsUsernameBackend(ModelBackend):
"""
Try to log the user in treating given username as email.
We do not want superusers here as well
"""
def authenticate(self, username, password):
try:
user = User.objects.get(email=username)
if user.check_password(password):
if user.is_superuser():
pass
else: return user
except User.DoesNotExist: return None
then in your admin.py you could override with
class UserCreationForm(CustomUserCreationForm):
"""
This overrides django's requirements on creating a user
We only need email, first_name, last_name
We're going to email the password
"""
def __init__(self, *args, **kwargs):
super(UserCreationForm, self).__init__(*args, **kwargs)
# let's require these fields
self.fields['email'].required = True
self.fields['first_name'].required = True
self.fields['last_name'].required = True
# let's not require these since we're going to send a reset email to start their account
self.fields['username'].required = False
self.fields['password1'].required = False
self.fields['password2'].required = False
Mine has a few other modifications, but this should get you on the right track.
You have to modify the username length field so that syncdb will create the proper length varchar and you also have to modify the AuthenticationForm to allow greater values as well or else your users won't be able to log in.
from django.contrib.auth.forms import AuthenticationForm
AuthenticationForm.base_fields['username'].max_length = 150
AuthenticationForm.base_fields['username'].widget.attrs['maxlength'] = 150
AuthenticationForm.base_fields['username'].validators[0].limit_value = 150

stuck with writing facebook authentication in django

This is the code that i've come up with inspired from django RemoteUserBackend its not yet complete, I am not sure where in normal backends or in remoteuserbackend for instance where exactly the authenticate method called from ? Sorry I am new to django and the userlog in process seems to work like magic
from django.contrib import ModelBackend
from django.contrib.auth.models import User, Permission
def facebook_login_required(orig_view):
def wrapper(request):
if not request.user.is_authenticated():
redirect_url = 'https://www.facebook.com/dialog/oauth?client_id=%s&redirect_uri=%s&scope=email,read_stream'%(SETTINGS.FB_APPID,request.getlocation)
HttpResponseRedirect(redirect_url)
else:
# user is logged in, its safe to process the view
return orig_view
return wrapper
class FacebookAuthBackend(ModelBackend):
def authenticate(self,userid):
"""
The ``userid`` passed here is considered trusted.This method
simply returns the ``User`` objects with the given id, else
it creates a new user with the this ``userid`` if the it does
not existz
"""
if not userid:
user = User(userid=userid)
user.save()
user = None
try:
user = User.objects.get(userid=userid)
except User.DoesNotExist:
pass
return user
def get_user(self,userid):
try:
User.objects.get(userid=userid)
except User.DoesNotExist:
return None
Well, you can always have a look at the source code and figure out how things work and with yours don't
https://github.com/omab/django-social-auth/blob/master/social_auth/backends/facebook.py

Django, request.user is always Anonymous User

I am using a custom authentication backend for Django (which runs off couchdb). I have a custom user model.
As part of the login, I am doing a request.user = user and saving the user id in session.
However, on subsequent requests, I am not able to retrieve the request.user. It is always an AnonymousUser. I can, however, retrieve the user id from the session and can confirm that the session cookie is being set correctly.
What am I missing?
I do not want to use a relational db as I want to maintain all my user data in couchdb.
Edit: I have written a class which does not inherit from Django's auth User. It, however, has the username and email attributes. For this reason, my backend does not return a class which derives from auth User.
The request.user is set by the django.contrib.auth.middleware.AuthenticationMiddleware.
Check django/contrib/auth/middleware.py:
class LazyUser(object):
def __get__(self, request, obj_type=None):
if not hasattr(request, '_cached_user'):
from django.contrib.auth import get_user
request._cached_user = get_user(request)
return request._cached_user
class AuthenticationMiddleware(object):
def process_request(self, request):
request.__class__.user = LazyUser()
return None
Then look at the get_user function in django/contrib/auth/__init__.py:
def get_user(request):
from django.contrib.auth.models import AnonymousUser
try:
user_id = request.session[SESSION_KEY]
backend_path = request.session[BACKEND_SESSION_KEY]
backend = load_backend(backend_path)
user = backend.get_user(user_id) or AnonymousUser()
except KeyError:
user = AnonymousUser()
return user
Your backend will need to implement the get_user function.
I too have custom authentication backend and always got AnonymousUser after successful authentication and login. I had the get_user method in my backend. What I was missing was that get_user must get the user by pk only, not by email or whatever your credentials in authenticate are:
class AccountAuthBackend(object):
#staticmethod
def authenticate(email=None, password=None):
try:
user = User.objects.get(email=email)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
#staticmethod
def get_user(id_):
try:
return User.objects.get(pk=id_) # <-- tried to get by email here
except User.DoesNotExist:
return None
Its easy to miss this line in the docs:
The get_user method takes a user_id – which could be a username,
database ID or whatever, but has to be the primary key of your User
object – and returns a User object.
It so happened that email is not primary key in my schema. Hope this saves somebody some time.
You say you've written a custom authentication backend, but in fact what you seem to have written is a complete custom authentication app, which doesn't interface with Django's contrib.auth.
If you want to use a non-relational database for your authentication data, all you need to do is create a class that provides two methods: get_user(user_id) and authenticate(**credentials). See the documentation. Once you have authenticated a user, you simply call Django's normal login methods. There should be no reason to manually set request.user or put anything into the session.
Update after edit That has nothing to do with it. There's no requirement that the user class derives from auth.models.User. You still just need to define a get_user method that will return an instance of your user class.
Please elaborate. If you are using a custom user model (which is different from a custom user PROFILE model), then you are basically on your own and the django.contrib.auth framework can not help you with authentication. If you are writing your own authentication system and are not using django.contrib.auth, then you need to turn that off because it seem to be interfering with your system.
In case you are using an API (Django-rest-framework) and accessing a view using a get, post, etc. methods.
You can get a user by sending the Bearer/JWT token corresponding to that user.
Wrong
# prints Anonymous User
def printUser(request):
print(request.user)
Correct
# using decorators
# prints username of the user
#api_view(['GET']) # or ['POST'] .... according to the requirement
def printUser()
print(request.user)
I had similar problem when I used custom authentication backend. I used field different than the primary key in the method get_user.
It directly solved after using primary key which must be number (not str)
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id) # <-- must be primary key and number
except User.DoesNotExist:
return None
After sending Token using Authorization header, the token will be gotten in dispatch function as bellow:
'''
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
So you are using django_role_permission's HasRoleMixin, the dispatch method of this mixin will hide dispatch of the view.
I think that the solution is to redefine the mixin of roles-permissions
user = authenticate(username=username, password=password)
if user is not None:
return render(request, 'home.html',{'user_id':user.id})
Added these in my view
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
and started getting original user