[PYTHON] Notes diverses sur le framework Django REST

http://www.django-rest-framework.org/

À propos du traitement de l'authentification à l'aide de jetons

Je voulais émettre un jeton lorsque je me suis authentifié pour la première fois avec un ID utilisateur et un mot de passe, puis inclure ce jeton dans la demande, donc je l'ai implémenté comme suit (utilisez la table des utilisateurs Django telle quelle) ..

Nouveau processus d'enregistrement des informations utilisateur

Lors de l'enregistrement des informations utilisateur dans la table User, seul le mot de passe est haché à l'aide de la bibliothèque Django et enregistré. https://docs.djangoproject.com/en/1.8/_modules/django/contrib/auth/hashers/#make_password

serializers.py


class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'password')
        write_only_fields = ('password')
        read_only_fields = ('id')
        
        def create(self, validated_data):
          """
S'inscrire après le hachage du mot de passe(django utilise la bibliothèque par défaut)
          """
          password = validated_data.get('password')
          validated_data['password'] = make_password(password)
          return User.objects.create(**validated_data)
        
        # ......

Génération de jetons

J'ai utilisé la fonction d'authentification par jeton du framework Django REST tel quel. http://www.django-rest-framework.org/api-guide/authentication/

settings.py


INSTALLED_APPS = (
    # .......
    'rest_framework.authtoken',
)

Ajouter un processus pour créer une table de jetons

models.py


@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    """
Lorsqu'un nouvel utilisateur est créé, TOKEN est automatiquement émis.
    """
    if created:
        Token.objects.create(user=instance)

Avec les paramètres ci-dessus, lorsqu'un utilisateur est enregistré dans la table User, un jeton est émis et stocké dans la table Token.

Émission de jetons

Attribuez gets_auth_token à n'importe quel URI et créez un point de terminaison pour que le client obtienne le jeton.

urls.py


from rest_framework.authtoken import views as auth_views
urlpatterns = patterns('',
    url(r'^api-token-auth/', auth_views.obtain_auth_token),
)

Si vous POSTEZ le fichier json contenant le nom d'utilisateur et le mot de passe comme indiqué ci-dessous, le jeton correspondant au nom d'utilisateur sera retourné.

$ curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"username":"test","password":"111111"}' https://127.0.0.1:8000/api/api-token-auth/

Lors de l'envoi d'une demande du client à un URI qui nécessite un jeton, il est OK si vous placez le jeton dans l'autorisation de l'en-tête HTTP comme suit.

$ curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'

Processus d'authentification à l'aide de jetons

S'il s'agit d'un processus d'authentification normal, si vous ajoutez les paramètres suivants à settings.py, il vérifiera le contenu du jeton et effectuera le processus d'authentification lorsqu'une demande arrive.

settings.py


REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    )
}

Cependant, si vous définissez ce paramètre, l'authentification par jeton sera effectuée par défaut pour les demandes adressées à tous les URI, donc si vous souhaitez modifier la méthode d'authentification pour certains URI, utilisez votre propre authentification, comme indiqué dans l'exemple ci-dessous. Vous pouvez définir une classe, y écrire le processus d'authentification et spécifier cette classe dans la classe de vue.

En passant, notez que le nom du champ Http Header spécifié sur le client est automatiquement préfixé par "HTTP_". Cela ressemble aux spécifications de Django.

authentications.py


class FooAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        #Évaluer le jeton fixe par défaut lors du POST
        if request.method == 'POST':
            default_token = request.META.get('HTTP_DEFAULT_TOKEN')
            try:
                token = System.objects.get(key='HTTP_DEFAULT_TOKEN')
            except Token.DoesNotExist:
                raise exceptions.AuthenticationFailed('error')

            if default_token != token.value:
                raise exceptions.AuthenticationFailed('error')

            return None
        #Si vous pouvez faire autre chose que POST, évaluez le jeton d'authentification émis pour chaque valeur enregistrée.
        else:
            auth_token = request.META.get('HTTP_AUTHORIZATION')
            if not auth_token:
                raise exceptions.AuthenticationFailed('Authentication token is none')
            try:
                user = Token.objects.get(key=auth_token.replace('Token ', ''))
            except Token.DoesNotExist:
                raise exceptions.AuthenticationFailed('error')

            return (user.user, None)

view.py


class FooViewSet(viewsets.ModelViewSet):
    queryset = Foo.objects.none()
    serializer_class = FooSerializer
    authentication_classes = (FooAuthentication, )
    
    # .......

Au contraire, si vous souhaitez vous authentifier uniquement avec certains URI, vous devez spécifier TokenAuthentication dans authentication_classes de la classe d'affichage.

À propos du code de test

Le code de test a utilisé le client API du framework REST. http://www.django-rest-framework.org/api-guide/testing/ Comme ça.

tests.py


class UserTests(APITestCase):
    def setUp(self):
        """
        setUp for testing
        """
        User.objects.create(username='user1', password='user1')
        User.objects.create(username='user2', password='user2')
        self.user1 = User.objects.get(username='user1')
        self.user2 = User.objects.get(username='user2')

    def test_user_list_normal1(self):
        """
        user-list: normal pattern
        """
        url = reverse('user-list')
        expected_data = {
            "count": 1,
            "next": None,
            "previous": None,
            "results": [{
                "id": 1,
                "username": "user1"
            }]
        }
        token = Token.objects.get(user=self.user1).key
        #Définir le jeton pour l'autorisation
        self.client.credentials(HTTP_AUTHORIZATION='Token ' + token)
        response = self.client.get(url, None, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        #Confirmez que json est renvoyé comme prévu
        self.assertEqual(response.data, expected_data)

Recommended Posts

Notes diverses sur le framework Django REST
Notes diverses sur le déploiement de l'application django sur Heroku
Comprendre la commodité de Django Rest Framework
Bases du framework Django REST
Astuces Django Rest Framework
Essayez de créer une application Todo avec le framework Django REST
Notes d'apprentissage pour la fonction migrations dans le framework Django (3)
[Django Rest Framework] Personnalisez la fonction de filtre à l'aide de Django-Filter
Notes d'apprentissage pour la fonction migrations dans le framework Django (1)
Bloc d'achoppement du framework Django REST
Framework Django REST avec Vue.js
Connectez-vous avec Django Rest Framework
Comment écrire une validation personnalisée dans Django REST Framework
[Django] Utiliser MessagePack avec le framework Django REST
Mémo Django
Créer une API REST pour faire fonctionner dynamodb avec le Framework Django REST
Mémo Django
Créer une API RESTful avec Django Rest Framework
Suppression logique dans Django, DRF (Django REST Framework)
Un outil administratif qui peut être créé immédiatement avec le framework ng-admin + Django REST
CRUD GET avec Nuxt & Django REST Framework ②
CRUD POST avec Nuxt & Django REST Framework
CRUD GET avec Nuxt & Django REST Framework ①
Django REST Framework + Considération de conception d'architecture propre
CRUD PUT, DELETE avec Nuxt & Django REST Framework
À propos du test
Notes de [Django] as_view ()
Remarques sur avec
Solution lorsque Not Found apparaît lors de la frappe de l'API de Django REST Framework de l'extérieur
Framework Django REST Un peu utile à savoir.
Implémenter la fonctionnalité de connexion JWT dans le framework Django REST
Notes sur Pytorch
Notes de connaissances nécessaires pour comprendre le framework Python
Implémentation de la fonction d'authentification dans Django REST Framework à l'aide de djoser
À propos de la file d'attente
Un peu d'informations addictives sur Cliff, le framework CLI
Créer une application Todo avec Django REST Framework + Angular
Plus de nouvelles méthodes d'authentification des utilisateurs avec Django REST Framework
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 1 ~
Créer une API autour de l'authentification des utilisateurs avec Django REST Framework
Lorsque vous souhaitez filtrer avec le framework Django REST
List, méthode pour les ressources imbriquées dans le framework Django REST
Implémentez l'API à une vitesse explosive en utilisant Django REST Framework
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 2 ~
Notes personnelles sur l'intégration de vscode et anaconda
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 3 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 4 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 5 ~
Implémenter des URL hiérarchiques avec des routeurs imbriqués drf dans le framework Django REST
Framework Web Django Python
Création d'une API qui renvoie des résultats d'inférence négatifs-positifs à l'aide de BERT dans le framework Django REST
Notes de céleri sur Django
À propos de la fonction Déplier
À propos de la commande de service
Le cadre Common Clk
Premier mémo divers sur Python
[Django] Renommer le projet
À propos de la matrice de confusion