Click to jump to the REST-Framework column directory

Authentication is the mechanism that associates an incoming request with a set of identifying credentials (for example, the user from whom the request is coming or the token signed by him), which can then be used by permission and restriction policies to determine whether the request should be allowed.

Note: Requesting credentials will not allow carrying credentials, only credential information that identifies the person making the request.

How is authentication determined

The authentication scheme is always defined as a list of classes, and RESTframework will attempt to authenticate each class in the list and will set request.user and request.auth to the return value of the first class that is authenticated successfully.

If you don’t have any classes through authentication request. The user will be set to django. Contrib. Auth. Models. AnonymousUser instance, and the request. The auth is set to None.

Request. user and request.auth for unauthenticated requests can be modified using the UNAUTHENTICATED_USER and UNAUTHENTICATED_TOKEN Settings.

Setting an Authentication Scheme

You can set the default authentication scheme globally using DEFAULT_AUTHENTICATION_CLASSES, for example:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication'.'rest_framework.authentication.SessionAuthentication']},Copy the code

You can also set special authentication methods in a separate view:

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView) :
    authentication_classes = [SessionAuthentication, BasicAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request, format=None) :
        content = {
            'user': unicode(request.user),  # `django.contrib.auth.User` instance.
            'auth': unicode(request.auth),  # None
        }
        return Response(content)
Copy the code

Or a view function:

@api_view(['GET'])
@authentication_classes([SessionAuthentication, BasicAuthentication])
@permission_classes([IsAuthenticated])
def example_view(request, format=None) :
    content = {
        'user': unicode(request.user),  # `django.contrib.auth.User` instance.
        'auth': unicode(request.auth),  # None
    }
    return Response(content)
Copy the code

Error response

Two different error codes may be appropriate when an unauthenticated request is rejected.

  • HTTP 401unauthorized
  • HTTP 403Permission denied

HTTP 401 responses must always include the wwW-authenticate header, which indicates how the client authenticates, and HTTP 403 responses do not include the www-authenticate header.

Apache mod_WSGi specific configuration

Note that if you deploy to Apache using mod_WSGI, the authorization header is not passed to the WSGI application by default because it is assumed that authentication will be handled by Apache and not at the application level.

If you are deploying to Apache and using any non-session-based authentication, you need to explicitly configure mod_wsGI to pass the required headers to the application, which can be done by specifying instructions in the appropriate context and setting the WSGIPassAuthorization to ‘On’.

# this can go in either server config, virtual host, directory or .htaccess
WSGIPassAuthorization On
Copy the code

Basic authentication

This Authentication scheme uses HTTP BasicAuthentication, which is signed against the user’s user name and password. BasicAuthentication is usually only suitable for testing. If BasicAuthentication Authentication succeeds, provide the following credentials:

  • request.user: the DjangoUserClass instance object
  • request.auth:None

The token authentication

This authentication scheme uses a simple token-based HTTP authentication scheme for client-server Settings such as local desktop and mobile clients. To use this TokenAuthentication scheme, You need to configure the authentication class to include TokenAuthentication and add the rest_Framework.authToken setting to your INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    'rest_framework.authtoken'
]
Copy the code

You also need to create a token for the user:

from rest_framework.authtoken.models import Token

token = Token.objects.create(user=...)
print(token.key)
Copy the code

For client authentication, the Token key should be included in the HTTP header Authorization. The key should be prefixed with a string literal Token and separated by a space, for example:

Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
Copy the code

Note: If you want to use different keywords in headers, such as Bearer, just subclass TokenAuthentication and set the keyword variable, if successful, TokenAuthentication will provide the following credentials:

  • request.user: the DjangoUserClass instance object
  • request.auth:rest_framework.authtoken.models.TokenInstance object of

Unauthorized authentication will be denied. An HTTP 401 Unauthorized status code is returned with a WWWW-Authenticate header, as shown in the following:

WWW-Authenticate: Token
Copy the code

You can also use curl to do token authentication tests:

The curl -x GET http://127.0.0.1:8000/api/example/ - H 'Authorization: 9944 b09199c62bcf9418ad846dd0e4bbdfc6ee4b Token'Copy the code

To generate the token

When you want each user to automatically generate a token, just capture the user’s post_save signal:

from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs) :
    if created:
        Token.objects.create(user=instance)
Copy the code

Note that you’ll need to place this code snippet in the installed models.py, or somewhere else Django will automatically load the import when it starts. If you’ve already created some users, you can use the following code snippet to generate tokens for existing users:

from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token

for user in User.objects.all():
    Token.objects.get_or_create(user=user)
Copy the code

The above method is token generation by means of signal capture, you can use the API method to generate the token back.

With TokenAuthentication, you might want to provide a mechanism for clients to obtain tokens with a given user name and password. The framework’s built-in view, the obtain_AUTH_token view behavior, provides such a method that you can use by simply registering in the URL configuration:

from rest_framework.authtoken import views
urlpatterns += [
    path('api-token-auth/', views.obtain_auth_token)
]
Copy the code

When you use the form to authenticate the request token, if the authentication is successful, the following JSON data is returned:

{"token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"}
Copy the code

Note that the default obtain_AUTH_token view explicitly uses JSON requests and responses instead of default renderer and parser classes in Settings. By default, no permissions or restrictions apply to the obtain_AUTH_Token view. If you want to use application restrictions, You need to override the view class and include it using the throttLE_classes property.

If you need a custom version of the OBtain_AUTH_Token view, you can do so by subclassing the ObtainAuthToken view class and then using it in the URL configuration.

For example, you can return user information other than the token value:

from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response

class CustomAuthToken(ObtainAuthToken) :

    def post(self, request, *args, **kwargs) :
        serializer = self.serializer_class(data=request.data,
                                           context={'request': request})
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        token, created = Token.objects.get_or_create(user=user)
        return Response({
            'token': token.key,
            'user_id': user.pk,
            'email': user.email
        })
Copy the code

You can also manually create tokens through the admin interface. If your service has a large user base, it is recommended that you use the TokenAdmin class to customize the monkey patch to suit your actual needs, more specifically by declaring the User field raw_fied:

# app/admin.py

TokenAdmin.raw_id_fields = ['user']
Copy the code

Django Manage generates tokens

Starting with v3.6.4, tokens can be generated using the Django command:

./manage.py drf_create_token <username>
Copy the code

This command will return the API token data to the specified user. If it does not exist, it will create:

Generated token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b for user user1
Copy the code

If you want to regenerate a token if it has expired or is broken, just add an optional argument -r:

./manage.py drf_create_token -r <username>
Copy the code

The Session authentication

This authentication scheme uses Django’s default back-end Session authentication for AJAX client requests running in the same context on the web site. If authenticated, SessionAuthentication will provide the following credentials:

  • request.userAuthenticate the User instance of the User
  • request.authIs equal to theNone

The HTTP 403 Forbidden status is returned for unauthorized and unauthenticated identities.

If you’re using an Ajax-style API with SessionAuthentication, you need to make sure that your token contains any “unsafe” HTTP method calls with a valid CSRF, For example, PUT, PATCH, POST, or DELETE requests. See the Django CSRF documentation for more details.

Warning: Always use Django’s standard login view when creating your login page. This will ensure that your login view is properly protected.

CSRF authentication in the framework works slightly differently from standard Django in that it requires support for both session-based and non-session-based authentication for the same view. This means that only authenticated requests require the CSRF token, and anonymous requests may be sent without the CSRF token. This behavior does not apply to login views where CSRF validation should always be applied.

Remote user authentication

With this authentication scheme, you delegate authentication to the Web server, which sets the REMOTE_USER environment variable.

To use it, you must set in AUTHENTICATION_BACKENDS django. Contrib. Auth. Backends. RemoteUserBackend (or subclass), By default RemoteUserBackend creates User objects for User names that do not yet exist. To change this behavior and other behaviors, see the Django documentation.

If the authentication succeeds, RemoteUserAuthentication provides the following credentials:

  • request.userIt will be a DjangoUserThe instance
  • request.authWill beNone

Consult your Web server’s documentation for information on configuring authentication methods, such as:

  • Apache Authentication How-To
  • NGINX (Restricting Access)

User-defined authentication mode

To implement a custom authentication scheme, inherit BaseAuthentication and override the.authenticate(self, request) method, returning a tuple of data (user, auth) if the authentication is successful, and None otherwise.

None, in some cases, may be an exception raised in the.authenticate() method in AuthenticationFailed, rather than returned.

In general, the approach you should take is:

Return None if no authentication is attempted, and any other authentication schemes in use will still be checked. If you try to authenticate and fail, raise the AuthenticationFailed exception, and an error response will be returned immediately, whether or not any permission checks have been made, and without checking any other authentication schemes. You can also override the.authenticate_header(self, request) method, which if implemented should return a string, This string will be used as the value of the wwW-Authenticate header in the HTTP 401 Unauthorized response.

If.authenticate_header() does not override this method, the authentication scheme will return an HTTP 403 Forbidden response when an unauthenticated request is denied access.

Note: You may see AttributeError reraised as WrappedAttributeError when custom authenticators are called on the.user or.auth attribute of the request object, which is necessary to prevent the original exception from being suppressed by external attribute access. Python does not recognize that the AttributeError source is from your custom authenticator, but instead assumes that the request object does not have.user or.auth attributes. These errors should be fixed or otherwise handled by the verifier.

For example, the following example authenticates the user identity specified by the USERNAME in the custom request header named x-username:

from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions

class ExampleAuthentication(authentication.BaseAuthentication) :
    def authenticate(self, request) :
        username = request.META.get('HTTP_X_USERNAME')
        if not username:
            return None

        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            raise exceptions.AuthenticationFailed('No such user')

        return (user, None)
Copy the code