-
-
Save herotux/911a0d4744845d9f7e3d35e2a69b720d to your computer and use it in GitHub Desktop.
django rest api framework session auth example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.contrib import admin | |
from .models import User | |
admin.site.register([User]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'), | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
@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.
Your LoginView is not working for me.
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
Same question from me, it's possible to authenticate as session with the token in localstorage ?