Django Rest Auth - Custom registration logic for social views - django

I'm building a REST API with Django Rest Framework and Django Rest Auth.
My users have a consumer profile.
class UserConsumerProfile(
SoftDeletableModel,
TimeStampedModel,
UniversallyUniqueIdentifiable,
Userable,
models.Model
):
def __str__(self):
return f'{self.user.email} ({str(self.uuid)})'
As you can see it consists of some mixins that give it a UUID, a timestamp and an updated field and a OneToOne relationship to the user. I use this consumerprofile in relations to link data to the user.
This consumerprofile should get created as soon as a user signs up.
Here is the serializer that I wrote for the registration:
from profiles.models import UserConsumerProfile
from rest_auth.registration.serializers import RegisterSerializer
class CustomRegisterSerializer(RegisterSerializer):
def custom_signup(self, request, user):
profile = UserConsumerProfile.objects.create(user=user)
profile.save()
I connected this serializer in the settings:
REST_AUTH_REGISTER_SERIALIZERS = {
"REGISTER_SERIALIZER": "accounts.api.serializers.CustomRegisterSerializer"
}
It works flawlessly when the users signs up using his email. But when he signs up using facebook, no consumer profile gets created.
I thought the social view would also use the register serializer when creating users? How can I run custom logic after a social sign up?
EDIT for the bounty:
Here are the settings that I use for Django Rest Auth:
# django-allauth configuration
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_CONFIRM_EMAIL_ON_GET = True
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 1
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
ACCOUNT_ADAPTER = 'accounts.adapter.CustomAccountAdapter'
SOCIALACCOUNT_ADAPTER = 'accounts.adapter.CustomSocialAccountAdapter'
SOCIALACCOUNT_PROVIDERS = {
'facebook': {
'METHOD': 'oauth2',
'SCOPE': ['email', 'public_profile', 'user_friends'],
'AUTH_PARAMS': {'auth_type': 'reauthenticate'},
'INIT_PARAMS': {'cookie': True},
'FIELDS': [
'id',
'email',
'name',
'first_name',
'last_name',
'verified',
'locale',
'timezone',
'link',
'gender',
'updated_time',
],
'EXCHANGE_TOKEN': True,
'LOCALE_FUNC': 'path.to.callable',
'VERIFIED_EMAIL': True,
'VERSION': 'v2.12',
}
}
# django-rest-auth configuration
REST_SESSION_LOGIN = False
OLD_PASSWORD_FIELD_ENABLED = True
REST_AUTH_SERIALIZERS = {
"TOKEN_SERIALIZER": "accounts.api.serializers.TokenSerializer",
"USER_DETAILS_SERIALIZER": "accounts.api.serializers.UserDetailSerializer",
}
REST_AUTH_REGISTER_SERIALIZERS = {
"REGISTER_SERIALIZER": "accounts.api.serializers.CustomRegisterSerializer"
}
And here are the custom adapters (in case they matter):
from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.utils import build_absolute_uri
from django.http import HttpResponseRedirect
from django.urls import reverse
class CustomAccountAdapter(DefaultAccountAdapter):
def get_email_confirmation_url(self, request, emailconfirmation):
"""Constructs the email confirmation (activation) url."""
url = reverse(
"accounts:account_confirm_email",
args=[emailconfirmation.key]
)
ret = build_absolute_uri(
request,
url
)
return ret
def get_email_confirmation_redirect_url(self, request):
"""
The URL to return to after successful e-mail confirmation.
"""
url = reverse(
"accounts:email_activation_done"
)
ret = build_absolute_uri(
request,
url
)
return ret
def respond_email_verification_sent(self, request, user):
return HttpResponseRedirect(
reverse('accounts:account_email_verification_sent')
)
class CustomSocialAccountAdapter(DefaultSocialAccountAdapter):
def get_connect_redirect_url(self, request, socialaccount):
"""
Returns the default URL to redirect to after successfully
connecting a social account.
"""
assert request.user.is_authenticated
url = reverse('accounts:socialaccount_connections')
return url
Lastly, here are the views:
from allauth.socialaccount.providers.facebook.views import \
FacebookOAuth2Adapter
from rest_auth.registration.views import SocialConnectView, SocialLoginView
class FacebookLogin(SocialLoginView):
adapter_class = FacebookOAuth2Adapter
class FacebookConnect(SocialConnectView):
adapter_class = FacebookOAuth2Adapter
I thought that if I connected the serializer like I did in the initial part of the question the register serializer logic would also get run when someone signs up using facebook.
What do I need to do to have that logic also run when someone signs up using facebook?
(If I can't fix it, I could make a second server request after each facebook sign up on the client side which creates the userconsumerprofile, but that would be kinda overkill and would introduce new code surface which leads to a higher likelihood of bugs.)

Looking briefly at the DefaultAccountAdapter and DefaultSocialAccountAdapter it may be an opportunity for you to override/implement the save_user(..) in your CustomAccountAdapter/CustomSocialAccountAdapter to setup the profile?
Looking just at code it seems that the DefaultSocialAccountAdapter.save_user will finally call the DefaultAccountAdapter.save_user.
Something like this maybe?
class CustomAccountAdapter(DefaultAccountAdapter):
def save_user(self, request, user, form, commit=True):
user = super(CustomAccountAdapter, self).save_user(request, user, form,
commit)
UserConsumerProfile.objects.get_or_create(user=user)
return user
There are a few other "hooks"/functions in the adapters that may we worth to investigate if the save_user doesn't work for your scenario.

The REGISTER_SERIALIZER that you created is only used by the RegisterView.
The social login & connect views use different serializers: SocialLoginSerializer and SocialConnectSerializer, that cannot be overwritten per settings.
I can think of two ways to achieve your desired behavior:
create serializers for the social login & connect views (inherriting the default serializers) and set them as serializer_class for the view,
use Django signals, especially the post_save signal for the User model and when an instance is created, create your UserConsumerProfile.

Related

Django Rest Framework Postman 'POST' request error

I'm still having this error when trying to do a post request from postman.
{
"username": [
"This field is required."
],
"password": [
"This field is required."
]
}
I can make the same post request successfully from my DRF localhost, but when i try on postman i get the error above.
How can I solve it?
Views.py
class PlayThingList(viewsets.ModelViewSet):
serializer_class = PlayThingSerializer
queryset = PlayThing.objects.all()
class UserViewset(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
Serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'password']
extra_kwargs = {'password': {
'write_only':True,
'required':True
}}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
Token.objects.create(user)
return user
urls.py
router = DefaultRouter()
router.register('playthings', PlayThingList, basename='playthings')
router.register('users', UserViewset)
urlpatterns = [
path('playmates/', include(router.urls)),
]
Project urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework.authtoken.views import obtain_auth_token
app_name = 'playthings'
urlpatterns = [
path('admin/', admin.site.urls),
path("", include('playthings.urls')),
path('auth/', obtain_auth_token)
]
UPDATE
I made some changes based on the error messages and guides in the comments and I can now create users.
Problem is, after sending the user credentials in the form, i get this error in postman.
Try adding the following in your POSTMAN
Headers section:
KEY
Value
Accept
application/json
Body section (choose raw or x-www-form-urlencoded):
KEY
Value
username
(your username)
password
(your password)
In your userviewset, you are using UserSerializer. This way you can not create users. To create a user you will have to extend registeruser functionality.
Check out the code from rest-framework and use the same logic in your create method of userviewset. if you want to register a user.
Registeruser is all together a different thing.
Rest framework by default has a url to register users, use that url, it will handle everything for you.
Problem Solved!
The issue was with the token create() method. I changed
create(user) to create(user=user)
ref: serializers.py
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
Token.objects.create(user=user)
return user
Thank you to everyone that helped!

How can I use `email` in "django-rest-framework-simplejwt" instead of `username` to generate token?

In django-rest-framework-simplejwt plugin username and password are used by default. But I wanted to use email instead of username. So, I did like below:
In serializer:
class MyTokenObtainSerializer(Serializer):
username_field = User.EMAIL_FIELD
def __init__(self, *args, **kwargs):
super(MyTokenObtainSerializer, self).__init__(*args, **kwargs)
self.fields[self.username_field] = CharField()
self.fields['password'] = PasswordField()
def validate(self, attrs):
# self.user = authenticate(**{
# self.username_field: attrs[self.username_field],
# 'password': attrs['password'],
# })
self.user = User.objects.filter(email=attrs[self.username_field]).first()
print(self.user)
if not self.user:
raise ValidationError('The user is not valid.')
if self.user:
if not self.user.check_password(attrs['password']):
raise ValidationError('Incorrect credentials.')
print(self.user)
# Prior to Django 1.10, inactive users could be authenticated with the
# default `ModelBackend`. As of Django 1.10, the `ModelBackend`
# prevents inactive users from authenticating. App designers can still
# allow inactive users to authenticate by opting for the new
# `AllowAllUsersModelBackend`. However, we explicitly prevent inactive
# users from authenticating to enforce a reasonable policy and provide
# sensible backwards compatibility with older Django versions.
if self.user is None or not self.user.is_active:
raise ValidationError('No active account found with the given credentials')
return {}
#classmethod
def get_token(cls, user):
raise NotImplemented(
'Must implement `get_token` method for `MyTokenObtainSerializer` subclasses')
class MyTokenObtainPairSerializer(MyTokenObtainSerializer):
#classmethod
def get_token(cls, user):
return RefreshToken.for_user(user)
def validate(self, attrs):
data = super(MyTokenObtainPairSerializer, self).validate(attrs)
refresh = self.get_token(self.user)
data['refresh'] = text_type(refresh)
data['access'] = text_type(refresh.access_token)
return data
In view:
class MyTokenObtainPairView(TokenObtainPairView):
"""
Takes a set of user credentials and returns an access and refresh JSON web
token pair to prove the authentication of those credentials.
"""
serializer_class = MyTokenObtainPairSerializer
And it works!!
Now my question is, how can I do it more efficiently? Can anyone give suggestion on this? Thanks in advance.
This answer is for future readers and therefore contains extra information.
In order to simplify the authentication backend, you have multiple classes to hook into. I would suggest to do option 1 (and optionally option 3, a simplified version of yours) below. Couple of notes before you read on:
Note 1: django does not enforce email as required or being unique on user creation (you can override this, but it's off-topic)! Option 3 (your implementation) might therefore give you issues with duplicate emails.
Note 1b: use User.objects.filter(email__iexact=...) to match the emails in a case insensitive way.
Note 1c: use get_user_model() in case you replace the default user model in future, this really is a life-saver for beginners!
Note 2: avoid printing the user to console. You might be printing sensitive data.
As for the 3 options:
Adjust django authentication backend with f.e. class EmailModelBackend(ModelBackend) and replace authenticate function.
Does not adjust token claims
Not dependent on JWT class/middleware (SimpleJWT, JWT or others)
Also adjusts other authentication types (Session/Cookie/non-API auth, etc.)
The required input parameter is still username, example below. Adjust if you dont like it, but do so with care. (Might break your imports/plugins and is not required!)
Replace django authenticate(username=, password=, **kwarg) from django.contrib.auth
Does not adjust token claims
You need to replace token backend as well, since it should use a different authentication, as you did above.
Does not adjust other apps using authenticate(...), only replaces JWT auth (if you set it up as such)
parameters is not required and therefore this option is less adviced).
Implement MyTokenObtainPairSerializer with email as claim.
Now email is sent back as JWT data (and not id).
Together with option 1, your app authentication has become username agnostic.
Option 1 (note that this also allows username!!):
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
class EmailorUsernameModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
Option 2:
Skipped, left to reader and not adviced.
Option 3:
You seem to have this covered above.
Note: you dont have to define MyTokenObtainPairView, you can use TokenObtainPairView(serializer_class=MyTokenObtainPairSerializer).as_view() in your urls.py. Small simplification which overrides the used token serializer.
Note 2: You can specify the identifying claim and the added data in your settings.py (or settings file) to use email as well. This will make your frontend app use the email for the claim as well (instead of default user.id)
SIMPLE_JWT = {
'USER_ID_FIELD': 'id', # model property to attempt claims for
'USER_ID_CLAIM': 'user_id', # actual keyword in token data
}
However, heed the uniqueness warnings given by the creators:
For example, specifying a "username" or "email" field would be a poor choice since an account's username or email might change depending on how account management in a given service is designed.
If you can guarantee uniqueness, you are all set.
Why did you copy and paste so much instead of subclassing? I got it to work with:
# serializers.py
from rest_framework_simplejwt.serializers import TokenObtainSerializer
class EmailTokenObtainSerializer(TokenObtainSerializer):
username_field = User.EMAIL_FIELD
class CustomTokenObtainPairSerializer(EmailTokenObtainSerializer):
#classmethod
def get_token(cls, user):
return RefreshToken.for_user(user)
def validate(self, attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user)
data["refresh"] = str(refresh)
data["access"] = str(refresh.access_token)
return data
And
# views.py
from rest_framework_simplejwt.views import TokenObtainPairView
class EmailTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializer
And of course
#urls.py
from rest_framework_simplejwt.views import TokenRefreshView
from .views import EmailTokenObtainPairView
url("token/", EmailTokenObtainPairView.as_view(), name="token_obtain_pair"),
url("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
The question has been a while but, I add +1 for #Mic's answer. By the way, wasn't it sufficient to update to TokenObtainPairSerializer only as following?:
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.serializers import (
TokenObtainPairSerializer, User
)
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
username_field = User.EMAIL_FIELD
class EmailTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializer
Let summarize the above solutions:
1- Create two app by Django command. One for the new token and the other for the user:
python manage.py startapp m_token # modified token
python manage.py startapp m_user # modified user
2- In the m_token, create the serializers.py and override the serializer to replace username with email field:
# serializers.py
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer, User
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
username_field = User.EMAIL_FIELD
3- In the m_token, override the view to replace the serializer with the new one:
# views.py
from rest_framework_simplejwt.views import TokenObtainPairView
from .serializer import CustomTokenObtainPairSerializer
class EmailTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializer
4- In the m_token, create the urls.py and give the paths as follows:
# urls.py
from django.urls import path
from .views import TokenObtainPairView
from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView
urlpatterns = [
path(r'token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path(r'token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path(r'token/verify/', TokenVerifyView.as_view(), name='token_verify'),
]
5- In the m_user, override the user model as follows:
# models.py
from django.contrib.auth.models import AbstractUser
class MUser(AbstractUser):
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ['username']
6- In the django project root, add AUTH_USER_MODEL = 'm_user.MUser' to setting.py.
I tested it in my project and it worked perfectly. I hope I did not miss anything. This way the swagger also shows "email" instead of "username" in the token parameters:
And in addition to #Mic's answer, remember to set USERNAME_FIELD = 'email' and may be REQUIRED_FIELDS = ['username'] in the User model.
For those using a custom User model, you simply can add those lines:
class User(AbstractUser):
...
email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
Then, in urls.py:
from rest_framework_simplejwt.views import TokenObtainPairView
urlpatterns = [
...
path('api/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
Using this code you can allow users to login using either username or email in the username field. You can add some lines to validate the email.
class TokenPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
raw_username = attrs["username"]
users = User.objects.filter(email=raw_username)
if(users):
attrs['username'] = users.first().username
# else:
# raise serializers.ValidationError("Only email is allowed!")
data = super(TokenPairSerializer, self).validate(attrs)
return data

How does Django RESTful Framework get user model from token from HTTP header?

I'm building my Django RESTful Framework to retrieve and post data for Mobile. I'm using Django-rest-auth (which is just all-auth with RESTful functionality; more info : http://django-rest-auth.readthedocs.io/en/latest/).
How does Django RESTful Framework (or Django) finds user's model when mobile sends user's token in HTTP header?
For instance:
HTTP METHOD: POST
headers : Authorization eyl3of9iskjfpjowpefjsopeff (This is token and random string)
body : {
post_title: "This is my first post"
post_content: "This is the content"
}
This is my setting:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
# 'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}
This is where I want to find a user model :
class CreatePost(generics.CreateAPIView):
def get_queryset(self, **kwargs):
owner = User.objects.filter(user= ##) # right here!
post_title =
post_content =
Or any other approach suggested?
Usually, your Token is simply a Django model, which is stored in your database.
It has a OneToOne relation to your User model and that's simply how they are related (in rest_framework.authtoken). You can see it in DRF source.
A direct examle:
from rest_framework import generics
from rest_framework import status
from rest_framework.authtoken.models import Token
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# You can directly import your Token model for usage
from .serializers import UserLoginSerializer
class UserLogin(generics.CreateAPIView):
serializer_class = UserLoginSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, _ = Token.objects.get_or_create(user=user)
# Here you either get a Token if it exists in your db
# Or generate it if it is not created yet
# See that you directly get the token with your user:
# Token.objects.get_or_create(user=user)
# You can also access it vice-versa: token.user <-> user.token
# Because it is a OneToOne relation
response_data = {
'id': user.id,
'token': token.key
}
headers = self.get_success_headers(serializer.data)
return Response(response_data, status=status.HTTP_200_OK, headers=headers)
Note: If you are using JWT, have a look at how a token is linked with the user.
In your case:
class CreatePost(generics.CreateAPIView):
def get_queryset(self, **kwargs):
owner = self.request.user
# Are you sure you don't want to get the current request user?
# Why you should filter with token?
post_title = ...
post_content = ...
Your authentication classes (in your case, JSONWebTokenAuthentication, it automatically sets request.user to the correct one and you can access it in your views).

REST REQUEST not returning correct response

I'm fairly new to REST and have been working on using Requests (Python), with Django, and the Django Rest Framework. I am trying to make a get request which returns all objects with a "priority" (Int field) value of 4. The problem is the query doesn't seem to be working and the GET request is returning all project objects. The structure looks correct and I'm able to change the pages using the exact same syntax so I'm not sure what I'm doing wrong. Here is everything I think you'd need, any help would be awesome. Thanks!
Generated URL = http://127.0.0.1:8000/api/projects/?priority=4
RestConnect.py{
local = 'http://localhost/'
base = 'http://127.0.0.1:8000/api/'
def sign_in(current_user, username, password):
response = current_user.get(base + 'api-auth/login/', auth=(username, password))
print response
print response.url
print response.reason
# Some of this is intentionally generic and a little rough (the way the session is being passed)
def find_priority(current_user, username, password):
find_projects = {"priority": "4"}
response = current_user.get(base + 'projects', params=find_projects, auth=(username, password))
print response
print response.url
print response.text
}
QueryTest.py {
import requests
import restconnect
current_user = requests.Session()
restconnect.sign_in(current_user, 'user', 'password')
restconnect.find_priority(current_user, 'user', 'password')
}
serializer.py {
from rest_framework import serializers, viewsets
import django_filters
from . models import Project
class ProjectFilter(django_filters.FilterSet):
class Meta:
model = Project
fields = ['name', 'status', 'priority']
class ProjectSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Project
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
filter_class = ProjectFilter
}

mongoengine and django auth, login

I am trying to implement login functionality using mongoengine and django.
I have included 'mongoengine.django.mongo_auth' in INSTALLED_APPS
Following are my settings.py from mongoengine site.
MONGOENGINE_USER_DOCUMENT = 'mongoengine.django.auth.User'
AUTH_USER_MODEL = 'mongo_auth.MongoUser'
SESSION_ENGINE = 'mongoengine.django.sessions'
AUTHENTICATION_BACKENDS = (
'mongoengine.django.auth.MongoEngineBackend',
)
This is from models.py
class UserInfo(User,DynamicDocument):
address = EmbeddedDocumentField(Address)
dob = DateTimeField(required = True)
sex = StringField(max_length = 1, choices = SEX)
primary_number = LongField(required = True)
And following is from views.py
def LoginOrCreateUser(request):
formAuth = AuthenticationForm(data=(request.POST or None))
if(request.method=='POST'):
if(formAuth.is_valid()):
if(formAuth.clean_email()):
if(formAuth.clean_password()):
formAuth.save(True)
user=authenticate(username=formAuth.cleaned_data['username'],password = formAuth.cleaned_data['password1'])
login(request,user)
return HttpResponse('New User Success')
This code gives me error <obj_id "user"> is NOT JSON serializable.
The error is raised for login, so I guess here login API is provided by django but the user we are providing to it is the value got from authenticate which is mongoengine's provided api.
I looked into the auth.py of django and mongoengine. So, we don't have login API in mongoengine. And the authenticate of django returns the user instance, while authenticate of mongoengine returns a string i.e. username.
Any suggestions here or mistakes I am making in the implementation here.
André I just tried you're example but it gives me
NameError at /game/
global name 'jsonResponse' is not defined
If I import jsonResponse like
from django.http import HttpResponse,JsonResponse
then gives me
ImportError at /game/ cannot import name JsonResponse
I just only want to manage simple user auth with my mongoengine backend.
Thanks.
1st question, are you trying to customize the User object? Or you want to use default Django User model? I ask because you should set MONGOENGINE_USER_DOCUMENT and AUTH_USER_MODEL if you do want to make a custom model.
I will show you how I'm authenticating using mongoengine x Django:
On settings.py
connect('localhost')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.dummy',
}
}
AUTHENTICATION_BACKENDS = (
'mongoengine.django.auth.MongoEngineBackend'
)
SESSION_ENGINE = 'mongoengine.django.sessions'
On views.py
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponse
def jsonResponse(responseDict):
return HttpResponse(simplejson.dumps(responseDict), mimetype='application/json')
def createSession(request):
if not request.is_ajax():
return jsonResponse({'error':True})
if not request.session.exists(request.session.session_key):
request.session.create()
data = extractDataFromPost(request)
email = data["email"]
password = data["password"]
try:
user = User.objects.get(username=email)
if user.check_password(password):
user.backend = 'mongoengine.django.auth.MongoEngineBackend'
user = authenticate(username=email, password=password)
login(request, user)
request.session.set_expiry(3600000) # 1 hour timeout
return jsonResponse(serializeUser(user))
else:
result = {'error':True, 'message':'Invalid credentials'}
return jsonResponse(result)
except User.DoesNotExist:
result = {'error':True, 'message':'Invalid credentials'}
return jsonResponse(result)
def serializeUser(user):
return simplejson.dumps({'email': user.email, 'username': user.username, 'id': str(user.id), 'firstName': user.first_name, 'lastName': user.last_name})
After reading lots of stuff I could make it work this way following MongoEngine User authentication (django).
I'm not setting anything on models.py since I use the default Django user model.
Regards