I am using django-social-auth for facebook login which creates a new user if it doesn't exist in the db, else updates the existing db entry. I think it checks for fb_username OR fb_uid in the database to check if the user exists or not.
Requirements:
In my application, i need to be able to create a user by manually inserting his info in db. And this row should be updated when the user logs_in with facebook.
So I manually created an entry with all the information of the user i.e. fb_username, fb_uid, email, first_name, last_name, hometown... etc.
But what happens when the user logs_in is, a new entry is created instead of updating the manually created entry. So i really don't understand what fields does it use to check if the user exists or not. What would be the best way to go from here?
Extra Info: I am extending the user model of django to UserProfile using a one-to-one relationship and AUTH_PROFILE_MODULE = 'accounts.UserProfile'
The only way to do it was editing this default pipeline
'social_auth.backends.pipeline.user.create_user',
by changing the
def create_user(backend,details,response,username,user=None,*args,**kwargs):
if user:
return {'user': user}
if not username:
return None
to
def create_user(backend,details,response,username,user=None,*args,**kwargs):
username = User.objects.get(u_name=username)
if username:
return {'user': username}
if not username:
return None
Related
After implementing DRF authtoken app, I deleted my previous superuser (because it did not have an auth token) and created a new one. Looking at the database, I see that the new superuser has an entry in authtoken_token table. It also has is_admin, is_staff, and is_superuser set to True. is_active is set to False but this was also set to False in the previous superuser and loging in to admin was not a problem.
When I enter credentials in admin page with is_active=False, it says:
"Please enter the correct email and password for a staff account. Note that both fields may be case-sensitive."
Before setting is_active=True, some answers from other SO questions I tried:
I made sure I'm not setting SESSION_COOKIE_SECURE = True. I'm not using this setting in dev environment anyways.
When I check the database, django_session table is there. When I try to authenticate, I do not see a new entry being created.
I do create my superuser via python manage.py createsuperuser command, same as I did before.
I also tried to change superuser pw via python manage.py changepassword .
My db is synced, I checked the tables after deleting and creating a new superuser and they are properly updated.
These steps did not change anything. Then I set is_active=True for the new superuser, and I was finally able to login. But why? Before DRF token authentication, my inactive superuser could login to admin. Now, it cannot, it should be active to login. What does this have to do with token authentication? (So my problem is solved, but I'm wondering how django and drf works behind the doors.)
You can take a look a the class TokenAuthentication (which inherit from BaseAuthentication) in the file rest_framework/authentication.py.
Here you will find the method :
def authenticate_credentials(self, key):
model = self.get_model()
try:
token = model.objects.select_related('user').get(key=key)
except model.DoesNotExist:
raise exceptions.AuthenticationFailed(_('Invalid token.'))
if not token.user.is_active:
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
return (token.user, token)
As you can say, there is a protection on token.user.is_active to forbid the connexion. Thus your problem on admin !
You can then ask "Why this system ?" Because thanks to that, when you delete a user, you just need to put is_active to False, no need to delete it (if you have FK link to the user with on_delete=models.CASCADE, it could have some unwanted consequences).
Have you created the superuser using this command
python manage.py createsuperuser
Enter your username:
password.
I'm migrating something from an old PHP/apache server to Django. I'm a bit stumped with the 'ModelForm'.
As far as I understand, a "Model" is the abstraction for persistent elements in my website/server - specifically this is something stored physically, say in a database, and defines the fields (read columns) in the DB.
I started moving the authentication part of the site, and discovered models, and specifically the User model (I made an empty User inheriting AbstractUser just in case I will ever need to extend things). Now I want to create a simple two field form, to authenticate login.
The form:
Username (which is a field of User, by default)
Password (Which is not).
Even the 'Username' needs a redefinition in the model form. So my questions:
What is the advantage of the model form (over just a form)? - seems like you're redefining fields anyway, and obviously sometimes adding fields on top of the model.
Specifically for authentication, I probably need to store my salted hash associated with the user somehow, compare my password using that and retrieve the user object. This is something I find very hard to find in the Django docs - they just have too much written on authentication, and not one full code example. Do I put this in the "validate" method of form, retrieving there an object and storing it in a session or something?
If there is a deeper relation between a model form and the associated model, I would like to know as well.
Simple django forms and modelforms have quite differences.
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
The above example illustrates that you don't have to write any form field in here. The model form will itself create a form which is based on the attributes provided in the model ('Article' in this example).
If you create a simple django form then it would be something like:
class ArticleForm(forms.Form):
some_field = forms.CharField(some_attrs)
...
The django User model provides you everything you need for authentication. When you want to create users just import django.contrib.auth.models.User and use create method to create objects. Then when you want to authenticate a user use authenticate method.
from django.contrib.auth import authenticate, login
def user_login(request):
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
# after authentication login the user or set cookies or modify the session or some other action can be taken
return HttpResponse("Some response or use render for html page")
username and password will be coming from your post request.
If you want to extend default Django user model you can use django user model as onetoonefield in your extended model.
class AppUser(models.Model):
user = models.OneToOneField(User)
... # other custom fields
I have a setup with django-rest-framework, rest-auth, allauth and facebook Oauth2. My problem here is that when I created an user using the facebook endpoint, the social user was created, the django user was also created but both have no username. Should I configure this somewhere?
The username field is no longer present, because it was deprecated with Graph API v2.0 one year ago...
See
https://developers.facebook.com/docs/apps/changelog#v2_0_graph_api
/me/username is no longer available.
Check if you're using the newest versions of your libraries.
you can set custom username by overriding DefaultSocialAccountAdapter
i just removed # from email and replaced by _ to generate username
#in setting added this
SOCIALACCOUNT_ADAPTER = 'trip2.users.adapter.SocialAdapter'
# and then override the Adapter
class SocialAdapter(DefaultSocialAccountAdapter):
def populate_user(self,
request,
sociallogin,
data):
"""
Hook that can be used to further populate the user instance.
For convenience, we populate several common fields.
Note that the user instance being populated represents a
suggested User instance that represents the social user that is
in the process of being logged in.
The User instance need not be completely valid and conflict
free. For example, verifying whether or not the username
already exists, is not a responsibility.
"""
username = data.get('username')
first_name = data.get('first_name')
last_name = data.get('last_name')
email = data.get('email')
name = data.get('name')
user = sociallogin.user
emailtouname = email.split('#')[0] + "_" + email.split('#')[1].split('.')[0]
user_email(user, valid_email_or_none(email) or '')
name_parts = (name or '').partition(' ')
user_field(user, 'first_name', first_name or name_parts[0])
user_field(user, 'last_name', last_name or name_parts[2])
user_username(user, username or emailtouname)
return user
You can pass a 'username' key along with other data retrieved via Facebook API. Or you can dig into allauth/socialaccount/adapter.py populate_user() method and customize the 'username' field (I simply make it equal to user email)
I want to increase the length of the username in django from 30 to around 80, I know it may be duplicate question but the previous answers are not working, for example https://kfalck.net/2010/12/30/longer-usernames-for-django
this is for Django 1.2.
Did anyone try similar hack for Django>1.5
Thanks in advance
In Django 1.5 and above, the recommended approach would be to create a custom user model. Then you can make the username field exactly as you want.
I had the same problem few days ago. Finally, I ended just with cutting off first 30 characters of the (old) username (into the new database table), and adding a custom authentication backend that will check the email instead of user name. Terrible hack I know, and I'm planning to fix it as soon as I have some time. The idea is following:
I already have a model class that has one-to-one relation with djangos auth.User. I will add another field there called full_username.
class MyCustomUserModel(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, related_name="custom_user")
full_username = models.CharField(max_length=80, ...)
...
Then, I'll add another custom authentication backend that will check this field as username. It would look something like this:
from django.contrib.auth.backends import ModelBackend
class FullUsernameAuthBackend(ModelBackend):
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.filter(custom_user__full_username=username)
# If this doesn't work, will use (the second case):
# user = MyCustomUserModel.objects.filter(full_username=username).user
if user.check_password(password):
return user
except UserModel.DoesNotExist:
# Adding exception MyCustomUserModel.DoesNotExist in "(the second case)"
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
UserModel().set_password(password)
After this, you need to change settings.py:
AUTHENTICATION_BACKENDS = (
"....FullUsernameAuthBackend",
# I will have the email auth backend here also.
)
I hope that it will work.
Custom User Models are a huge change to make and aren't always compatible with apps. I solved it by running this very pragmatic migration. Note this only solves it at the database level.
migrations.RunSQL("alter table auth_user alter column username type varchar(254);")
I've just integrated Django-Social-Auth (DSA) v0.7.23 using django 1.5 with a custom User model and auth/login is working fine except for the username field which is not being stored in my custom User model.
Stepping through the DSA code it appears to explicitly remove the username which was passed back by facebook. Here is the function in question that pops the username off:
#classmethod
def username_field(cls, values):
user_model = cls.user_model()
if hasattr(user_model, 'USERNAME_FIELD'):
# Django 1.5 custom user model, 'username' is just for internal
# use, doesn't imply that the model should have an username field
values[user_model.USERNAME_FIELD] = values.pop('username') # Username removed
return values
How can I go about getting the username that was passed back from facebook and not having it be explicitly removed by DSA?
I believe a work around would be to create a custom pipeline that generates a username. However I was wondering if anyone else encountered this scenario before and leveraged anything that already exists within DSA (i.e. a particular settings.py configuration)
Thanks.
The original username is available in the details attribute passed to pipeline functions, take this for example:
def generated_username(user, details, *args, **kwargs):
username = details['username']
user.your_field = username
user.save()
It's worth noting that the username is popped from values if you have a USERNAME_FIELD defined in your custom model.