Mongoengine User Authentication - django

Does anyone have specific examples of using the authentication from Mongoengine?
A couple questions I have are:
extending the User class
from mongoengine.django.auth import User
from mongoengine import *
class User(User):
location = GeoPointField()
When I create a user with no documents are saved
User.create_user('bob','bobpass','bobsaget#fullhouse.gov')
User.objects
>>>[]
explicitly call the .save() method has the same affect
Can the User class not be inherited?
Also
Is there a login() method like in the standard authentication backend?
I am starting to feel like I am trying to put a square peg in a round hole with MongoDB and Django...

I haven't used MongoEngine, but I've been looking at it documentation.
First, don't use the User name for your extension, there could be name clashes. Call it for example Profile:
from mongoengine.django.auth import User
from mongoengine import *
class Profile(User):
location = GeoPointField()
If that is not working, try:
class Profile(Document):
user = ReferenceField(User)
location = GeoPointField()
For your login question, look at this.

create instance.
user = User.create_user('bob','bobpass','bobsaget#fullhouse.gov')
user.save()
or
user = User(username='bob', password='bobpass', email='bobsaget#fullhouse.gov')
user.save()
or
user = User()
user.username = 'bob'
user.password = 'bobpass'
user.email = 'bobsaget#fullhouse.gov'
user.save()

Related

how to receive username with token by django rest authetication?

I am using django Django=2.1.7 and rest framework djangorestframework=3.9.2 This is my url for login
path('rest-auth/login', include('rest_auth.urls')),
When I enter username and password I got the token from rest API. But I want my user detail like name, id etc to show in my react components. Please help me how to achieve. I have seen many answers on StackOverflow even the official documentation is not descriptive https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication
If you use rest-auth you can get the id, username, email, first_name and last_name of the logged user using this URL: http://localhost:8000/rest-auth/user/
The mentioned package provides us the ability to override the settings
In the login process, the response comes from either TOKEN_SERIALIZER or JWT_SERIALIZER. In your case, I assume that you are not using the JWT method.
So, create a new serializer class as per your desired structure and wire it up using REST_AUTH_SERIALIZERS settings dictionary.
Here is one sample
#serializer.py
from django.contrib.auth import get_user_model
from rest_framework import serializers
from rest_framework.authtoken.models import Token
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('id', 'username', 'email')
class MyCustomTokenSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Token
fields = ('key', 'user')
and in your settings.py,
REST_AUTH_SERIALIZERS = {
'TOKEN_SERIALIZER': 'path.to.custom.MyCustomTokenSerializer',
...
...
}
There is no way to automatically populate user data once a user logs in. You should just be able to take the username the user entered during the login process, save it in a variable, and after receipt of token make another API call to get the user information.

Django: Show View after password entry

How can I return a View only after letting the user enter a password which is checked against the link?
class Foo(models.Model):
url = models.CharField(max_length=10) #a randomly created ASCII-string
name = models.CharField(max_length=10)
password = models.CharField(max_length=10)
url_patterns = [path('foo/<url>/admin', views.foo, name='foo_admin'),]
So a user goes to url:
localhost/foo/bar
now he should enter the correct password to see the content of model Foo with url='bar'.
If you are using class based views you will want the UserPassesTestMixin.
If you are using function based views you will want the user_passes_test decorator.
Both are described here. Both will essentially divert to the process flow to anything you define. In your case you will want to divert to whatever your using for password checking.
In case you haven't implemented a password scheme you can also read about the default django authentication at the same link.

Longer username in Django 1.7

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);")

Why Django does not check email integrity when creating a new user?

I don't understand this behaviour. Let's say I open a Django shell and type:
from django.contrib.auth.models import User
user = User.objects.create(username="toto", email="titi")
Why does Django let me create this user (with an invalid email) without raising an error?
I have the same "no verification behaviour" creating a user in a POST in my API created with tastypie.
The question is:
As Django does not seem to check this by itself, where am I supposed to perform this kind of verifications sothat I don't have to write them several times (since a user can be created in several ways like website, API, etc.)?
Thanks.
Django doesn't implicitly do any validation if you just call .create() or .save() - you need to explicitly use model validation, or save the object via a
ModelForm. Your example with model validation would look like this:
user = User(username="toto", email="titi")
try:
user.full_clean()
except ValidationError as e:
# handle the error...
pass
user.save()
Or using a ModelForm:
class UserForm(forms.ModelForm):
class Meta:
model = User
f = UserForm(dict(username="toto", email="titi"))
if f.is_valid():
user = f.save()
else:
# handle error, ...
pass
Both model validation and ModelForms invoke the model field's validators, so in the case of the User's email, no additional work is needed for validation. If you need to do custom validation, you can do this in the ModelForm class - it is common to have a forms.py file in the app as a central place for Forms and ModelForms.
The same goes for Tastypie - the default configuration assumes the data submitted is valid. You can override this with the FormValidation class, which uses a Django Form or ModelForm for its validation. A full example would look something like this:
class UserResource(ModelResource):
class Meta:
queryset = User.objects.all()
validation = FormValidation(form_class=UserForm) # UserForm from above
# more options here....

Django-Registration: Account creation that asks for First Name/Last Name?

This question is a follow-up to the solution explained by Muki here:
Problem in adding custom fields to django-registration
I have installed and have been successfully using the Django-registration package. By default, when you create an account using this package, it asks for your username, email address and password. I want it to also ask for (optional) first name + last name. Muki's answer at the link above explains how to do so.
However, Muki left out what should go into the file that he creates in the custom/forms.py. I need to know what the name of the class I should create in here is and what the field definitions should look like.
Can someone please post a sample forms.py that I can use to accomplish what I'm trying to do?
If your custom backend is in the custom folder, then custom/forms.py could be something like this:
from django import forms
from registration.forms import RegistrationForm
class RegistrationFormWithName(RegistrationForm):
first_name = forms.CharField(required=False)
last_name = forms.CharField(required=False)
This adds your two optional fields to the default registration form. To tell your custom backend to use this new form instead of the default you need to change the get_form_class method in custom/__init__.py Muki's answer explains how to do that.
Of course, you'll also need to handle saving the data from the first_name and last_name fields.
Edit:
Your custom/__init__.py needs to look something like this:
from registration.backends.default import DefaultBackend
from registration.backends.custom.forms import RegistrationFormWithName
class CustomBackend(DefaultBackend):
def get_form_class(self, request):
return RegistrationFormWithName
And custom/urls.py needs a line like this:
url(r'^register/$', register, {'backend': 'registration.backends.custom.CustomBackend'}, name='registration_register'),
Change the name of the CustomBackend class in both files to whatever you're calling your new backend.
Have a look at the default backend source to get an idea of the other methods you can override. Hope that helps.
This link explains the process well and works with django-registration 1.0
here are a few extra pointers in addition to the above code.
To update the first name change this in the models.py
def user_registered_callback(sender, user, request, **kwargs):
profile = ExUserProfile(user = user)
profile.is_human = bool(request.POST["is_human"])
user.first_name = request.POST["firstname"]
user.save()
profile.save()
user_registered.connect(user_registered_callback)
and in the forms.py file
class ExRegistrationForm(RegistrationForm):
is_human = forms.BooleanField(label = "Are you human?:")
firstname = forms.CharField(max_length=30)
lastname = forms.CharField(max_length=30)
finally to see the changes on the form create an appropriate template. The profile can be seen in the admin by creating a file called admin.py in your app and write the following code
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from prof.models import ExUserProfile
admin.site.unregister(User)
class UserProfileInline(admin.StackedInline):
model = ExUserProfile
class UserProfileAdmin(UserAdmin):
inlines = [ UserProfileInline, ]
admin.site.register(User, UserProfileAdmin)