Writing in the front

Log in to Django REST Framework JWT

The authentication mode of JWT mentioned above is very convenient to configure and implement. However, the company’s project login authentication is diverse, such as SSO, Oauth and other authentication methods of internal system;

Today we will talk about how to customize login authentication in the FRAMEWORK of DRF.

The code in this article is developed based on the Django REST Framework (3)

The text start

1. Prepare the SSO interface

New demo/mock_view.py This file is used to simulate the interface for SSO login and token authentication

  • Login User password login is supported (for logical integrity only)
  • Token verification does not implement specific logic but only demonstrates overall logic

Note: when setting a cookie, it will directly affect the default behavior of the browser. If the company expects a token to access all services, it must configure the top-level domain name. Similar to baidu.com rather than baike.baidu.com;

# 1. Add files

from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication

from django.conf.urls import url


class AnyAuthentication(BaseAuthentication) :
    def authenticate(self, request) :
        return


@api_view(['POST'])
@authentication_classes((AnyAuthentication,))
@permission_classes((AllowAny, ))
def login(request) :
    token = request.COOKIES.get('auth'."auth")
    password = request.data.get('password'.' ')
    username = request.data.get('username'.' ')

    # user center check username password
    response = Response({'user': "user_info".'token': token})
    response.set_cookie('auth', token, domain="0.0.0.0", expires=30 * 24 * 60 * 60)
    return response


@api_view(['GET'])
@authentication_classes((AnyAuthentication,))
@permission_classes((AllowAny,))
def check_token(request, token) :

    token = request.COOKIES.get('auth')

    # user center check token ...

    data = {
        "user_info": {
            "username": "admin"."user_id": 1
        },
        "token": token
    }
    return Response(data)


mock_urls = [
    url('^login/', login),
    url(r"^check_token/(? P
      
       [A-Za-z0-9]+)/$"
      , check_token)
]
2.Urls.py new routefrom .mock_view import mock_urls
...

urlpatterns += mock_urls
Copy the code

2. Install dependencies

Services that mock remotely need to import a package of network requests

pipenv install requests
Copy the code

3. Implement logic

The utils/authentication.py file is added

Add utils/authentication.py
import requests

from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication
from django.utils.translation import ugettext_lazy
from django.contrib.auth.models import User


class MyAuthentication(BaseAuthentication) :

    def authenticate(self, request) :

        token = request.COOKIES.get('auth')

        if token is not None:
            username = self.check_token(token)
            if username is not None:
                return User.objects.get(username=username), token
            else:
                raise exceptions.AuthenticationFailed(ugettext_lazy('Invalid token.'))

    @staticmethod
    def check_token(token) :
        # Simulate request token validation
        response = requests.get("http://localhost:8000/check_token/" + token)
        if response.status_code == 200:
            return response.json().get("user_info", {}).get("username")

2.Added authentication configuration in settings.py'DEFAULT_AUTHENTICATION_CLASSES': (
        'utils.authentication.MyAuthentication'.'rest_framework_jwt.authentication.JSONWebTokenAuthentication'.'rest_framework.authentication.SessionAuthentication'.'rest_framework.authentication.BasicAuthentication',),Copy the code

4. Verify the results

The default BASCI authentication mode
$ curl -H 'Accept: application/json; indent=4'{-u admin: admin http://127.0.0.1:8000/api/article/1/"id": 1,
    "creator": "admin"."tag": "Modern Poetry"."title": "如果"."content": "I'll never think of you again in this life, except in some night, when tears are wet with tears, if you will."
}

# Customize the token authentication mode
$ curl -H 'Accept: application/json; indent=4' --cookie "auth=123"{http://127.0.0.1:8000/api/article/1/"id": 1,
    "creator": "admin"."tag": "Modern Poetry"."title": "如果"."content": "I'll never think of you again in this life, except in some night, when tears are wet with tears, if you will."
}
Copy the code

conclusion

Now that the logic for custom authentication is complete, some questions about authentication are summarized:

  1. What is the execution order of custom authentication and default authentication?

A: In the Settings file we configured the DEFAULT_AUTHENTICATION_CLASSES ancestor. The default execution sequence is top-down validation, and if both fail, a failed exception is thrown, which is eventually recovered by DRF and returned to the front end.

  1. What should I pay attention to when implementing MyAuthentication?

A: BaseAuthentication is the source code below, you can see that all DRF authentication needs to inherit BaseAuthentication and must be authenticate, it should be noted that the return value is a tuple (user, token); This, of course, is the underlying logic behind using Request. user in Django to get the current user.

class BaseAuthentication:
    """ All authentication classes should extend BaseAuthentication. """

    def authenticate(self, request) :
        """ Authenticate the request and return a two-tuple of (user, token). """
        raise NotImplementedError(".authenticate() must be overridden.")

    def authenticate_header(self, request) :
        """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """
        pass

Copy the code
  1. So our system supports multiple authentication methods, no matter what kind of login can be quickly supported; Life is short. I use Python.

The following is a snippeof the Request class in Django to illustrate the order of execution and the retrieval of the User object

In the end, both the self-implemented authentication and DRF authentication inherit BaseAuthentication and authenticate; In fact, the source code is not difficult, but your heart.

The resources

  • DRF certification