[PYTHON] Faisons une application qui affaiblit les nerfs avec Vue.js et Django-Rest-Framework [Partie 5] ~ Authentification des utilisateurs ~

<< Partie 4 | Partie 6 >>

Création d'utilisateurs personnalisés

Lors du démarrage d'un nouveau projet, il est fortement recommandé de créer un modèle utilisateur personnalisé, même si l'utilisateur par défaut est suffisant.

C'est officiellement le cas, alors créez un utilisateur personnalisé.

création d'applications utilisateurs

$ django-admin startapp users

Ajoutez l'application créée à settings.py

settings.py


.
..
...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'corsheaders',
    'users', #Postscript
]
...
..
.

Création de modèle utilisateur

users/models.py


from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, UserManager
from django.utils import timezone

# Create your models here.
class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField('username', max_length=150, unique=True)
    first_name = models.CharField('first name', max_length=30, blank=True)
    last_name = models.CharField('last name', max_length=150, blank=True)
    email = models.EmailField('email address', blank=True)
    is_staff = models.BooleanField('is_staff', default=False)
    is_active = models.BooleanField('is_active', default=True)
    date_joined = models.DateTimeField('date joined', default=timezone.now)

    objects = UserManager()

    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']

    class Meta:
        verbose_name = 'user'
        verbose_name_plural = 'users'

    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def get_full_name(self):
        """
        Return the first_name plus the last_name, with a space in between.
        """
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()

    def get_short_name(self):
        """Return the short name for the user."""
        return self.first_name

    def email_user(self, subject, message, from_email=None, **kwargs):
        """Send an email to this user."""
        send_mail(subject, message, from_email, [self.email], **kwargs)

Création de classe UserManager

users/user_manager.py



from django.contrib.auth.base_user import BaseUserManager

class UserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, username, email, password, **extra_fields):
        """
        Create and save a user with the given username, email, and password.
        """
        if not username:
            raise ValueError('The given username must be set')
        email = self.normalize_email(email)
        username = self.model.normalize_username(username)
        user = self.model(username=username, email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, username, email=None, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(username, email, password, **extra_fields)

    def create_superuser(self, username, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(username, email, password, **extra_fields)

Modifier le modèle utilisateur créé

users/models.py


.
..
...
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin #Supprimer UserManager
from users.user_manager import UserManager #Importez votre propre classe UserManager
...
..
.

Ajouté à settings.py afin que le modèle utilisateur personnalisé soit utilisé comme modèle d'authentification

settings.py


.
..
...
AUTH_USER_MODEL = 'users.User'
...
..
.

Migration de base de données

$ python3 manage.py makemigrations
Migrations for 'users':
  users/migrations/0001_initial.py
    - Create model User

Il y a une erreur dans Migrate ... C'est une histoire de création d'un utilisateur personnalisé depuis le début et de migration de DB ... pleurer

$ python3 manage.py migrate
$ python3 manage.py migrate
Traceback (most recent call last):
  File "manage.py", line 21, in <module>
    main()
  File "manage.py", line 17, in main
    execute_from_command_line(sys.argv)
...
..
.
django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency users.0001_initial on database 'default'.

Modifier settings.py et urls.py

settings.py


.
..
...
INSTALLED_APPS = [
    # 'django.contrib.admin',Commenter
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'corsheaders',
    'users',
]
...
..
.

config/urls.py


.
..
...
urlpatterns = [
    # path('admin/', admin.site.urls), #Commenter
    url('api/', include(ROUTER.urls)),
]

Mon grand encore

$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: auth, contenttypes, sessions, users
Running migrations:
  Applying users.0001_initial... OK

Décommentez settings.py et urls.py et assurez-vous que la migration de la base de données n'entraîne pas d'erreur.

$ python3 manage.py makemigrations
No changes detected

$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, users
Running migrations:
  No migrations to apply.

résolu. (Veuillez créer un superutilisateur.)

Créons une API en utilisant User.

Créez serializers.py directement sous l'annuaire des utilisateurs

users/serializers.py


from rest_framework.serializers import ModelSerializer
from users.models import User

class UserSerializer(ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

Créer une vue

users/views.py


from rest_framework.viewsets import ModelViewSet
from users.models import User
from users.serializers import UserSerializer

# Create your views here.
class UserViewSet(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

Modifier urls.py

config/urls.py


"""config URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.conf.urls import include, url
from rest_framework import routers
from users.views import UserViewSet #ajouter à

ROUTER = routers.DefaultRouter()
ROUTER.register('users', UserViewSet) #ajouter à


urlpatterns = [
    path('admin/', admin.site.urls),
    url('api/', include(ROUTER.urls)),
]

Accédez à http://127.0.0.1:8000/api/users/.

image.png

Si vous créez un utilisateur par POST à partir d'ici, le mot de passe sera créé en texte brut. C'est une situation terrible.

Modifiez serializers.py afin que le mot de passe soit haché.

users/serializers.py


from rest_framework.serializers import ModelSerializer
from users.models import User
from django.contrib.auth.hashers import make_password #ajouter à

class UserSerializer(ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

    #Remplacer la méthode de création
    def create(self, validated_data):
        password = validated_data.get('password', None)
        if password is not None:
            validated_data['password'] = make_password(password)
        return super().create(validated_data);

Installation et configuration de la bibliothèque d'authentification (JWT)

Cette fois, nous utiliserons la méthode JWT. Définir comme officiellement.

pip3 install djangorestframework-jwt

settings.py


.
..
...
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}

config/urls.py


"""config URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.conf.urls import include, url
from rest_framework import routers
from users.views import UserViewSet
from rest_framework_jwt.views import obtain_jwt_token #ajouter à

ROUTER = routers.DefaultRouter()
ROUTER.register('users', UserViewSet)


urlpatterns = [
    path('admin/', admin.site.urls),
    url('api/', include(ROUTER.urls)),
    url('api-token-auth/', obtain_jwt_token), #ajouter à
]

Lorsque j'accède à http://127.0.0.1:8000/api/users/, le résultat n'est plus affiché. image.png

Obtenez un jeton avec curl

curl -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}' http://127.0.0.1:8000/api-token-auth/

Résultat d'acquisition

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNTgwOTIwNDcwLCJlbWFpbCI6ImFkbWluQGFkbWluLmNvLmpwIn0.O8h4Js07Nr3aILHZyoAYlPklSGX-TJZs6k6tpB4xd0Y"}(concentration) tabatadikinoMBP:concentratio tabatadaiki$ curl -X "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNTgwOTIwMzA5LCJlbWFpbCI6ImFkbWluQGFkbWluLmNvLmpwIn0.vvKtzWk6d0qhDpwy3PgyiZ6ovkw-2JHJyn7mf25XrsU"

Obtenez des utilisateurs en spécifiant le jeton obtenu

curl -H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNTgwOTIwMzA5LCJlbWFpbCI6ImFkbWluQGFkbWluLmNvLmpwIn0.vvKtzWk6d0qhDpwy3PgyiZ6ovkw-2JHJyn7mf25XrsU" http://127.0.0.1:8000/api/users/

Résultat d'acquisition

[{"id":1,"password":"pbkdf2_sha256$150000$lLUvsL7bxcSs$/PhUu6BtJVaQtuhfkI6rj7frwvLHbpVFjFoCY7S8+0w=","last_login":null,"is_superuser":true,"username":"admin","first_name":"","last_name":"","email":"[email protected]","is_staff":true,"is_active":true,"date_joined":"2020-02-04T15:23:57.201798Z","groups":[],"user_permissions":[]},{"id":2,"password":"yktgy780","last_login":null,"is_superuser":true,"username":"tabatadaiki","first_name":"tabata","last_name":"daiki","email":"[email protected]","is_staff":true,"is_active":true,"date_joined":"2020-02-05T15:21:26.470920Z","groups":[],"user_permissions":[]},{"id":3,"password":"akasatana","last_login":null,"is_superuser":true,"username":"a","first_name":"a","last_name":"a","email":"","is_staff":true,"is_active":true,"date_joined":"2020-02-05T15:27:12.682966Z","groups":[],"user_permissions":[]},{"id":5,"password":"pbkdf2_sha256$150000$v9YkaBjzyGXP$VyQEp/yk6gWf8FEvI7C9TxCBANgXi9JxivQ/wjkjjpg=","last_login":null,"is_superuser":true,"username":"tabata","first_name":"tabata","last_name":"tabata","email":"","is_staff":true,"is_active":true,"date_joined":"2020-02-05T15:41:50.518882Z","groups":[],"user_permissions":[]}]

Il semble que j'ai pu m'authentifier.

Recommended Posts

Faisons une application qui affaiblit les nerfs avec Vue.js et Django-Rest-Framework [Partie 6] ~ Authentification utilisateur 2 ~
Faisons une application qui affaiblit les nerfs avec Vue.js et Django-Rest-Framework [Partie 5] ~ Authentification des utilisateurs ~
Créons une application qui affaiblit les nerfs avec Vue.js et Django-Rest-Framework [Partie 2] ~ Configuration de Vue ~
Faisons une application qui affaiblit les nerfs avec Vue.js et Django-Rest-Framework [Partie 1] ~ Django setup ~
Faisons une application qui affaiblit les nerfs avec Vue.js et Django-Rest-Framework [Partie 4] ~ Construction MySQL et migration de base de données avec Docker ~
Faisons une application WEB pour l'annuaire téléphonique avec flacon Partie 2
Faisons une application WEB pour l'annuaire téléphonique avec flacon Partie 3
Faisons une application WEB pour l'annuaire téléphonique avec flacon Partie 4
Essayez de créer un jeu simple avec Python 3 et iPhone
Créons une application Mac avec Tkinter et py2app
Créons un client de socket Web avec Python. (Authentification par jeton d'accès)
Faisons une interface graphique avec python.
Faisons une rupture de bloc avec wxPython
Faisons un graphe avec python! !!
Faisons un spacon avec xCAT
Créez un thermomètre avec Raspberry Pi et rendez-le visible sur le navigateur Partie 4
Faisons un jeu de shiritori avec Python
Faisons la voix lentement avec Python
Faisons un langage simple avec PLY 1
Créez un framework Web avec Python! (1)
Faisons une IA à trois yeux avec Pylearn 2
Faisons un bot Twitter avec Python!
Créez un framework Web avec Python! (2)
Fabriquez un thermomètre avec Raspberry Pi et rendez-le visible sur le navigateur Partie 3
Créons une application Web de conversion A vers B avec Flask! De zéro ...
Essayez de créer une application Web avec Vue.js et Django (édition Mac) - (1) Construction d'environnement, création d'application
Remplaçons UWSC par Python (5) Faisons un robot
Créons une application capable de rechercher des images similaires avec Python et Flask Part1
Créons une application capable de rechercher des images similaires avec Python et Flask Part2
Faisons un Makefile et construisons-le (super débutant)
[Jouons avec Python] Créer un livre de comptes de ménage
Facilitons un peu la gestion des dépendances avec pip
[Super facile] Faisons un LINE BOT avec Python.
Créez facilement des systèmes d'authentification, de gestion des utilisateurs et multilingues avec Flask-AppBuilder
Créez un plug-in tky2jgd sans praticité avec QGIS Partie 2
Associez Python Enum à une fonction pour la rendre appelable
Créer un plug-in tky2jgd sans praticité avec QGIS Partie 1
Créez des RPG 2D avec Ren'Py (3) - Boutique d'objets et d'outils
Faisons un diagramme sur lequel on peut cliquer avec IPython
Fabriquez un thermomètre BLE et obtenez la température avec Pythonista3