Call Django's authenticate function with the request object (#5295)

As of Django 1.11 the `authenticate` function accepts a request as an
additional argument. This commit fixes compatibility between newer Django
versions and custom authentication backends which already depend on the request
object.

See also:

[Django 1.11 release](https://docs.djangoproject.com/en/1.11/releases/1.11/)

```
authenticate() now passes a request argument to the authenticate() method of
authentication backends. Support for methods that don’t accept request as the
first positional argument will be removed in Django 2.1.
```
This commit is contained in:
Jascha Geerds 2017-10-05 11:43:49 +02:00 committed by Tom Christie
parent d138f30a86
commit 161dc2df2c
4 changed files with 20 additions and 8 deletions

View File

@ -6,12 +6,13 @@ from __future__ import unicode_literals
import base64 import base64
import binascii import binascii
from django.contrib.auth import authenticate, get_user_model from django.contrib.auth import get_user_model
from django.middleware.csrf import CsrfViewMiddleware from django.middleware.csrf import CsrfViewMiddleware
from django.utils.six import text_type from django.utils.six import text_type
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import HTTP_HEADER_ENCODING, exceptions from rest_framework import HTTP_HEADER_ENCODING, exceptions
from rest_framework.compat import authenticate
def get_authorization_header(request): def get_authorization_header(request):
@ -83,17 +84,18 @@ class BasicAuthentication(BaseAuthentication):
raise exceptions.AuthenticationFailed(msg) raise exceptions.AuthenticationFailed(msg)
userid, password = auth_parts[0], auth_parts[2] userid, password = auth_parts[0], auth_parts[2]
return self.authenticate_credentials(userid, password) return self.authenticate_credentials(userid, password, request)
def authenticate_credentials(self, userid, password): def authenticate_credentials(self, userid, password, request=None):
""" """
Authenticate the userid and password against username and password. Authenticate the userid and password against username and password
with optional request for context.
""" """
credentials = { credentials = {
get_user_model().USERNAME_FIELD: userid, get_user_model().USERNAME_FIELD: userid,
'password': password 'password': password
} }
user = authenticate(**credentials) user = authenticate(request=request, **credentials)
if user is None: if user is None:
raise exceptions.AuthenticationFailed(_('Invalid username/password.')) raise exceptions.AuthenticationFailed(_('Invalid username/password.'))

View File

@ -1,7 +1,7 @@
from django.contrib.auth import authenticate
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from rest_framework.compat import authenticate
class AuthTokenSerializer(serializers.Serializer): class AuthTokenSerializer(serializers.Serializer):
@ -17,7 +17,8 @@ class AuthTokenSerializer(serializers.Serializer):
password = attrs.get('password') password = attrs.get('password')
if username and password: if username and password:
user = authenticate(username=username, password=password) user = authenticate(request=self.context.get('request'),
username=username, password=password)
if user: if user:
# From Django 1.10 onwards the `authenticate` call simply # From Django 1.10 onwards the `authenticate` call simply

View File

@ -13,7 +13,8 @@ class ObtainAuthToken(APIView):
serializer_class = AuthTokenSerializer serializer_class = AuthTokenSerializer
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data) serializer = self.serializer_class(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user'] user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user) token, created = Token.objects.get_or_create(user=user)

View File

@ -407,3 +407,11 @@ def include(module, namespace=None, app_name=None):
return include(module, namespace, app_name) return include(module, namespace, app_name)
else: else:
return include((module, app_name), namespace) return include((module, app_name), namespace)
def authenticate(request=None, **credentials):
from django.contrib.auth import authenticate
if django.VERSION < (1, 11):
return authenticate(**credentials)
else:
return authenticate(request=request, **credentials)