Skip to content

Instantly share code, notes, and snippets.

@herotux
Forked from padurets/admin.py
Created May 11, 2018 11:32
Show Gist options
  • Save herotux/911a0d4744845d9f7e3d35e2a69b720d to your computer and use it in GitHub Desktop.
Save herotux/911a0d4744845d9f7e3d35e2a69b720d to your computer and use it in GitHub Desktop.
django rest api framework session auth example
from django.contrib import admin
from .models import User
admin.site.register([User])
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
class UserManager(BaseUserManager):
def _create_user(self, email, password, is_staff, is_superuser, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
now = timezone.now()
user = self.model(
email=self.normalize_email(email),
is_staff=is_staff,
is_active=True,
is_superuser=is_superuser,
last_login=now,
joined_at=now,
**extra_fields
)
user.set_password(password)
user.save(using=self._db)
return user
def get_by_natural_key(self, username):
return self.get(**{'{}__iexact'.format(self.model.USERNAME_FIELD): username})
def create_user(self, email, password, **extra_fields):
return self._create_user(email, password, False, False, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
return self._create_user(email, password, True, True, **extra_fields)
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField('Email', max_length=255, unique=True)
name = models.CharField('Name', max_length=255, blank=True)
is_staff = models.BooleanField('Is staff', default=False)
is_active = models.BooleanField('Is active', default=True)
joined_at = models.DateTimeField('Joined at', default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
# def __str__(self):
# return str(self.pk)
class Meta:
verbose_name = 'User'
verbose_name_plural = 'Users'
def get_full_name(self):
return self.name
def get_short_name(self):
return self.name
from django.contrib.auth import authenticate
from rest_framework import serializers
from .models import User
from .validators import validate_username
class LoginSerializer(serializers.Serializer):
email = serializers.EmailField()
password = serializers.CharField()
def validate(self, attrs):
user = authenticate(username=attrs['email'], password=attrs['password'])
if not user:
raise serializers.ValidationError('Incorrect email or password.')
if not user.is_active:
raise serializers.ValidationError('User is disabled.')
return {'user': user}
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'id',
'last_login',
'email',
'name',
'is_active',
'joined_at',
'password'
)
read_only_fields = ('last_login', 'is_active', 'joined_at')
extra_kwargs = {
'password': {'required': True, 'write_only': True},
'name': {'required': True}
}
@staticmethod
def validate_email(value):
return validate_username(value)
def create(self, validated_data):
return User.objects.create_user(
validated_data.pop('email'),
validated_data.pop('password'),
**validated_data
)
from django.conf.urls import url
from rest_framework import routers
from . import views
urlpatterns = [
url(r'^register/$', views.RegisterView.as_view(), name='user-register'),
url(r'^login/$', views.LoginView.as_view(), name='user-login'),
url(r'^logout/$', views.LogoutView.as_view(), name='user-logout'),
url(r'^current/$', views.UserView.as_view(), name='user-current'),
]
from django.core.exceptions import ValidationError
from .models import User
def validate_username(username):
if User.objects.filter(**{'{}__iexact'.format(User.USERNAME_FIELD): username}).exists():
raise ValidationError('User with this {} already exists'.format(User.USERNAME_FIELD))
return username
from django.conf import settings
from django.contrib.auth import login, logout
from rest_framework import views, generics, response, permissions, authentication
from .serializers import UserSerializer, LoginSerializer
class CsrfExemptSessionAuthentication(authentication.SessionAuthentication):
def enforce_csrf(self, request):
return
class LoginView(views.APIView):
permission_classes = (permissions.AllowAny,)
authentication_classes = (CsrfExemptSessionAuthentication,)
def post(self, request):
serializer = LoginSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
login(request, user)
return response.Response(UserSerializer(user).data)
class LogoutView(views.APIView):
def post(self, request):
logout(request)
return response.Response()
class RegisterView(generics.CreateAPIView):
serializer_class = UserSerializer
permission_classes = (permissions.AllowAny,)
def perform_create(self, serializer):
user = serializer.save()
user.backend = settings.AUTHENTICATION_BACKENDS[0]
login(self.request, user)
class UserView(generics.RetrieveAPIView):
serializer_class = UserSerializer
lookup_field = 'pk'
def get_object(self, *args, **kwargs):
return self.request.user
@Munsterberg
Copy link

Django recommends enforcing CSRF tokens for login, does marking as exempt not open up potential vulnerabilities?

@SvenNussgruber
Copy link

@Munsterberg You can always replace CsrfExemptSessionAuthentication with SessionAuthentication.
authentication_classes = (SessionAuthentication,)
This will include a csrf token with your response and set it in cookies

@SergeMerzliakov
Copy link

How does this work with Javascript, where JS function dynamically calls a Django REST? Does it need to get the credentials (be they user/password, token) from a cookie?

@BATTLEROYALXS
Copy link

How does this work with Javascript, where JS function dynamically calls a Django REST? Does it need to get the credentials (be they user/password, token) from a cookie?

Same question from me, it's possible to authenticate as session with the token in localstorage ?

@anpct
Copy link

anpct commented Oct 19, 2020

@BATTLEROYALXS
Session authentication is used to avoid storing tokens in local storage as they are vulnerable to attacks.
The browser automatically send the session cookie to the server when it identifies the URL.

@PritpalSingh786
Copy link

Your LoginView is not working for me.

@dopeboy
Copy link

dopeboy commented Dec 27, 2021

This was helpful, thank you. I needed this line in my LogoutView to get it working:

authentication_classes = (CsrfExemptSessionAuthentication,)

I also found this example helpful to complement this gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment