Guide pour créer une application de blog complète avec Django en utilisant la méthodologie TDD et PostgreSQL (authentification utilisateur partiellement sécurisée

Patricia Arquette
Libérer: 2024-10-18 18:18:03
original
832 Les gens l'ont consulté

Bienvenue à tous ! Dans la partie précédente, nous avons établi un processus d'enregistrement sécurisé des utilisateurs pour notre application de blog Django. Cependant, après une inscription réussie, nous avons été redirigés vers la page d’accueil. Ce comportement sera modifié une fois que nous aurons implémenté l'authentification des utilisateurs. L'authentification des utilisateurs garantit que seuls les utilisateurs autorisés peuvent accéder à certaines fonctionnalités et protège les informations sensibles.
Guide to Building a Complete Blog App with Django using TDD Methodology and PostgreSQL (Part  Secure User Authentication
Dans cette série, nous construisons une application de blog complète, guidée par le diagramme entité-relation (ERD) suivant. Pour cette fois, nous nous concentrerons sur la mise en place d’un processus d’authentification sécurisé des utilisateurs. Si vous trouvez ce contenu utile, aimez, commentez et abonnez-vous pour rester informé lorsque la prochaine partie sera publiée.
Guide to Building a Complete Blog App with Django using TDD Methodology and PostgreSQL (Part  Secure User Authentication
Ceci est un aperçu de l'apparence de notre page de connexion une fois que nous aurons implémenté la fonctionnalité de connexion. Si vous n'avez pas lu les parties précédentes de la série, je vous recommande de le faire, car ce tutoriel est une continuation des étapes précédentes.

D'accord, commençons !!

Django est livré avec une application intégrée appelée contrib.auth, qui simplifie pour nous la gestion de l'authentification des utilisateurs. Vous pouvez vérifier le fichier blog_env/settings.py, sous INSTALLED_APPS, vous verrez que l'authentification est déjà répertoriée.

# django_project/settings.py
INSTALLED_APPS = [
    # "django.contrib.admin",
    "django.contrib.auth",  # <-- Auth app
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

L'application d'authentification nous fournit plusieurs vues d'authentification pour gérer la connexion, la déconnexion, le changement de mot de passe, la réinitialisation du mot de passe, etc. Cela signifie que la fonctionnalité d'authentification essentielle, telle que la connexion de l'utilisateur, l'enregistrement et les autorisations, est prête à être utilisée sans avoir besoin pour tout construire à partir de zéro.

Dans ce didacticiel, nous nous concentrerons uniquement sur les vues de connexion et de déconnexion, et couvrirons le reste des vues dans les parties ultérieures de la série.

1. Créez un formulaire de connexion

En suivant notre approche TDD, commençons par créer des tests pour le formulaire de connexion. Puisque nous n'avons pas encore créé de formulaire de connexion, accédez au fichier users/forms.py et créez une nouvelle classe héritant d'AuthenticationForm.

# users/forms.py
from django.contrib.auth import AuthenticationForm

class LoginForm(AuthenticationForm):


Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Une fois le formulaire défini, nous pouvons ajouter des cas de test dans users/tests/test_forms.py pour vérifier sa fonctionnalité.

# users/tests/test_forms.py

#   --- other code

class LoginFormTest(TestCase):
  def setUp(self):
    self.user = User.objects.create_user(
      full_name= 'Tester User',
      email= 'tester@gmail.com',
      bio= 'new bio for tester',
      password= 'password12345'
    )

  def test_valid_credentials(self):
    """
    With valid credentials, the form should be valid
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': 'password12345',
      'remember_me': False
    }

    form = LoginForm(data = credentials)
    self.assertTrue(form.is_valid())

  def test_wrong_credentials(self):
    """
    With wrong credentials, the form should raise Invalid email or password error
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': 'wrongpassword',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertIn('Invalid email or password', str(form.errors['__all__']))

  def test_credentials_with_empty_email(self):
    """
    Should raise an error when the email field is empty
    """
    credentials = {
      'email': '',
      'password': 'password12345',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertFalse(form.is_valid())
    self.assertIn('This field is required', str(form.errors['email']))

  def test_credentials_with_empty_password(self):
    """
    Should raise error when the password field is empty
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': '',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertFalse(form.is_valid())
    self.assertIn('This field is required', str(form.errors['password']))
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ces tests couvrent des scénarios tels qu'une connexion réussie avec des informations d'identification valides, un échec de connexion avec des informations d'identification non valides et la gestion appropriée des messages d'erreur.

La classe AuthenticationForm fournit une validation de base par défaut. Cependant, avec notre LoginForm, nous pouvons adapter son comportement et ajouter toutes les règles de validation nécessaires pour répondre à nos exigences spécifiques.

# django_project/settings.py
INSTALLED_APPS = [
    # "django.contrib.admin",
    "django.contrib.auth",  # <-- Auth app
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Nous avons créé un formulaire de connexion personnalisé qui comprend les champs suivants : e-mail, mot de passe et remember_me. La case à cocher Remember_me permet aux utilisateurs de maintenir leur session de connexion au fil des sessions de navigateur.

Étant donné que notre formulaire étend AuthenticationForm, nous avons remplacé certains comportements par défaut :

  • ** Méthode __init__** : nous avons supprimé le champ du nom d'utilisateur par défaut du formulaire pour l'aligner sur notre authentification par e-mail.
  • méthode clean() : Cette méthode valide les champs email et mot de passe. Si les informations d'identification sont valides, nous authentifions l'utilisateur à l'aide du mécanisme d'authentification intégré de Django.
  • Méthode confirm_login_allowed() : Cette méthode intégrée offre la possibilité d'une vérification supplémentaire avant la connexion. Vous pouvez remplacer cette méthode pour implémenter des vérifications personnalisées si nécessaire. Maintenant, nos tests devraient réussir :
# users/forms.py
from django.contrib.auth import AuthenticationForm

class LoginForm(AuthenticationForm):


Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

2. Créez notre vue de connexion

2.1 Créer des tests pour la vue de connexion

Comme nous n'avons pas encore la vue pour la connexion, naviguons vers le fichier users/views.py et créons une nouvelle classe héritant du LoginView de l'application d'authentification

# users/tests/test_forms.py

#   --- other code

class LoginFormTest(TestCase):
  def setUp(self):
    self.user = User.objects.create_user(
      full_name= 'Tester User',
      email= 'tester@gmail.com',
      bio= 'new bio for tester',
      password= 'password12345'
    )

  def test_valid_credentials(self):
    """
    With valid credentials, the form should be valid
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': 'password12345',
      'remember_me': False
    }

    form = LoginForm(data = credentials)
    self.assertTrue(form.is_valid())

  def test_wrong_credentials(self):
    """
    With wrong credentials, the form should raise Invalid email or password error
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': 'wrongpassword',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertIn('Invalid email or password', str(form.errors['__all__']))

  def test_credentials_with_empty_email(self):
    """
    Should raise an error when the email field is empty
    """
    credentials = {
      'email': '',
      'password': 'password12345',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertFalse(form.is_valid())
    self.assertIn('This field is required', str(form.errors['email']))

  def test_credentials_with_empty_password(self):
    """
    Should raise error when the password field is empty
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': '',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertFalse(form.is_valid())
    self.assertIn('This field is required', str(form.errors['password']))
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Au bas du fichier users/tests/test_views.py, ajoutez ces cas de test

# users/forms.py

# -- other code
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm # new line
from django.contrib.auth import get_user_model, authenticate # new line


# --- other code

class LoginForm(AuthenticationForm):
  email = forms.EmailField(
    required=True,
    widget=forms.EmailInput(attrs={'placeholder': 'Email','class': 'form-control',})
  )
  password = forms.CharField(
    required=True,
    widget=forms.PasswordInput(attrs={
                                'placeholder': 'Password',
                                'class': 'form-control',
                                'data-toggle': 'password',
                                'id': 'password',
                                'name': 'password',
                                })
  )
  remember_me = forms.BooleanField(required=False)

  def __init__(self, *args, **kwargs):
    super(LoginForm, self).__init__(*args, **kwargs)
    # Remove username field

    if 'username' in self.fields:
      del self.fields['username']

  def clean(self):
    email = self.cleaned_data.get('email')
    password = self.cleaned_data.get('password')

    # Authenticate using email and password
    if email and password:
      self.user_cache = authenticate(self.request, email=email, password=password)
      if self.user_cache is None:
        raise forms.ValidationError("Invalid email or password")
      else:
        self.confirm_login_allowed(self.user_cache)
    return self.cleaned_data

  class Meta:
    model = User
    fields = ('email', 'password', 'remember_me')
Copier après la connexion
Copier après la connexion
Copier après la connexion

Nous devons nous assurer que ces tests échouent à ce stade.

2.2 Créer une vue de connexion

Dans le fichier users/views.py en bas du fichier ajoutez le code ci-dessous :

(.venv)$ python3 manage.py test users.tests.test_forms
Found 9 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.........
----------------------------------------------------------------------
Ran 9 tests in 3.334s
OK
Destroying test database for alias 'default'...
Copier après la connexion
Copier après la connexion

Dans le code ci-dessus, nous accomplissons ce qui suit :

  • Définissez l'attribut form_class : Nous spécifions notre LoginForm personnalisé comme attribut form_class puisque nous n'utilisons plus l'AuthentificationForm par défaut.
  • Remplacer la méthode form_valid : Nous remplaçons la méthode form_valid, qui est appelée lorsque des données de formulaire valides ont été publiées. Cela nous permet de mettre en œuvre un comportement personnalisé une fois que l'utilisateur s'est connecté avec succès.
  • Gérer l'expiration de la session : si l'utilisateur ne coche pas la case Remember_me, la session expirera automatiquement à la fermeture du navigateur. Cependant, si la case Remember_me est cochée, la session durera pendant la durée définie dans settings.py. La durée de session par défaut est de deux semaines, mais nous pouvons la modifier à l'aide de la variable SESSION_COOKIE_AGE dans settings.py. Par exemple, pour fixer l'âge des cookies à 7 jours, nous pouvons ajouter la ligne suivante dans nos paramètres :
# -- other code 
from .forms import CustomUserCreationForm, LoginForm
from django.contrib.auth import get_user_model, views
# -- other code

class CustomLoginView(views.LoginForm):


Copier après la connexion
Copier après la connexion

Pour connecter votre fonctionnalité de connexion personnalisée et permettre aux utilisateurs d'accéder à la page de connexion, nous définirons des modèles d'URL dans le fichier users/urls.py. Ce fichier mappera des URL spécifiques (/log_in/ dans ce cas) aux vues correspondantes (CustomLoginView). De plus, nous inclurons un chemin pour la fonctionnalité de déconnexion à l'aide de LogoutView intégré à Django.

# django_project/settings.py
INSTALLED_APPS = [
    # "django.contrib.admin",
    "django.contrib.auth",  # <-- Auth app
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Tout semble être en ordre, mais nous devrions préciser où rediriger les utilisateurs en cas de connexion et de déconnexion réussies. Pour ce faire, nous utiliserons les paramètres LOGIN_REDIRECT_URL et LOGOUT_REDIRECT_URL. Au bas de votre fichier blog_app/settings.py, ajoutez les lignes suivantes pour rediriger les utilisateurs vers la page d'accueil :

# users/forms.py
from django.contrib.auth import AuthenticationForm

class LoginForm(AuthenticationForm):


Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Maintenant que nous avons l'URL de connexion, mettons à jour notre SignUpView dans le fichier users/views.py pour rediriger vers la page de connexion une fois l'inscription réussie.

# users/tests/test_forms.py

#   --- other code

class LoginFormTest(TestCase):
  def setUp(self):
    self.user = User.objects.create_user(
      full_name= 'Tester User',
      email= 'tester@gmail.com',
      bio= 'new bio for tester',
      password= 'password12345'
    )

  def test_valid_credentials(self):
    """
    With valid credentials, the form should be valid
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': 'password12345',
      'remember_me': False
    }

    form = LoginForm(data = credentials)
    self.assertTrue(form.is_valid())

  def test_wrong_credentials(self):
    """
    With wrong credentials, the form should raise Invalid email or password error
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': 'wrongpassword',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertIn('Invalid email or password', str(form.errors['__all__']))

  def test_credentials_with_empty_email(self):
    """
    Should raise an error when the email field is empty
    """
    credentials = {
      'email': '',
      'password': 'password12345',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertFalse(form.is_valid())
    self.assertIn('This field is required', str(form.errors['email']))

  def test_credentials_with_empty_password(self):
    """
    Should raise error when the password field is empty
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': '',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertFalse(form.is_valid())
    self.assertIn('This field is required', str(form.errors['password']))
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Nous mettrons également à jour nos SignUpTexts, en particulier test_signup_correct_data(self), pour refléter le nouveau comportement et garantir que nos modifications sont correctement testées.

# users/forms.py

# -- other code
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm # new line
from django.contrib.auth import get_user_model, authenticate # new line


# --- other code

class LoginForm(AuthenticationForm):
  email = forms.EmailField(
    required=True,
    widget=forms.EmailInput(attrs={'placeholder': 'Email','class': 'form-control',})
  )
  password = forms.CharField(
    required=True,
    widget=forms.PasswordInput(attrs={
                                'placeholder': 'Password',
                                'class': 'form-control',
                                'data-toggle': 'password',
                                'id': 'password',
                                'name': 'password',
                                })
  )
  remember_me = forms.BooleanField(required=False)

  def __init__(self, *args, **kwargs):
    super(LoginForm, self).__init__(*args, **kwargs)
    # Remove username field

    if 'username' in self.fields:
      del self.fields['username']

  def clean(self):
    email = self.cleaned_data.get('email')
    password = self.cleaned_data.get('password')

    # Authenticate using email and password
    if email and password:
      self.user_cache = authenticate(self.request, email=email, password=password)
      if self.user_cache is None:
        raise forms.ValidationError("Invalid email or password")
      else:
        self.confirm_login_allowed(self.user_cache)
    return self.cleaned_data

  class Meta:
    model = User
    fields = ('email', 'password', 'remember_me')
Copier après la connexion
Copier après la connexion
Copier après la connexion

2.3 Créer un modèle pour la connexion

Créez ensuite un fichier users/templates/registration/login.html avec votre éditeur de texte et incluez le code suivant :

(.venv)$ python3 manage.py test users.tests.test_forms
Found 9 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.........
----------------------------------------------------------------------
Ran 9 tests in 3.334s
OK
Destroying test database for alias 'default'...
Copier après la connexion
Copier après la connexion

Nous ajouterons la fonctionnalité Mot de passe oublié plus tard dans cette série, mais maintenant ce n'est qu'un lien mort.
Guide to Building a Complete Blog App with Django using TDD Methodology and PostgreSQL (Part  Secure User Authentication
Maintenant, mettons à jour notre modèle layout.html pour inclure les liens de connexion, d'inscription et de déconnexion.

# -- other code 
from .forms import CustomUserCreationForm, LoginForm
from django.contrib.auth import get_user_model, views
# -- other code

class CustomLoginView(views.LoginForm):


Copier après la connexion
Copier après la connexion

Dans notre modèle, nous vérifions si l'utilisateur est authentifié. Si l'utilisateur est connecté, nous affichons le lien de déconnexion et le nom complet de l'utilisateur. Sinon, nous affichons les liens de connexion et d'inscription.
Maintenant, faisons tous les tests

# users/tests/test_views.py

# -- other code

class LoginTests(TestCase):
  def setUp(self):
    User.objects.create_user(
      full_name= 'Tester User',
      email= 'tester@gmail.com',
      bio= 'new bio for tester',
      password= 'password12345'
    )
    self.valid_credentials = {
      'email': 'tester@gmail.com',
      'password': 'password12345',
      'remember_me': False
    }

  def test_login_url(self):
    """User can navigate to the login page"""
    response = self.client.get(reverse('users:login'))
    self.assertEqual(response.status_code, 200)

  def test_login_template(self):
    """Login page render the correct template"""
    response = self.client.get(reverse('users:login'))
    self.assertTemplateUsed(response, template_name='registration/login.html')
    self.assertContains(response, '<a class="btn btn-outline-dark text-white" href="/users/sign_up/">Sign Up</a>')

  def test_login_with_valid_credentials(self):
    """User should be log in when enter valid credentials"""
    response = self.client.post(reverse('users:login'), self.valid_credentials, follow=True)
    self.assertEqual(response.status_code, 200)
    self.assertRedirects(response, reverse('home'))
    self.assertTrue(response.context['user'].is_authenticated)
    self.assertContains(response, '<button type="submit" class="btn btn-danger"><i class="bi bi-door-open-fill"></i> Log out</button>')

  def test_login_with_wrong_credentials(self):
    """Get error message when enter wrong credentials"""
    credentials = {
      'email': 'tester@gmail.com',
      'password': 'wrongpassword',
      'remember_me': False
    }

    response = self.client.post(reverse('users:login'), credentials, follow=True)
    self.assertEqual(response.status_code, 200)
    self.assertContains(response, 'Invalid email or password')
    self.assertFalse(response.context['user'].is_authenticated)
Copier après la connexion

3. Testez si tout fonctionne comme il se doit dans notre navigateur

Maintenant que nous avons configuré la fonctionnalité de connexion et de déconnexion, il est temps de tout tester dans notre navigateur Web. Démarrons le serveur de développement

# django_project/settings.py
INSTALLED_APPS = [
    # "django.contrib.admin",
    "django.contrib.auth",  # <-- Auth app
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Accédez à la page d'inscription et saisissez des informations d'identification valides. Après une inscription réussie, vous devriez être redirigé vers la page de connexion. Entrez les informations utilisateur dans le formulaire de connexion et une fois connecté, cliquez sur le bouton de déconnexion. Vous devriez ensuite être déconnecté et redirigé vers la page d'accueil. Enfin, vérifiez que vous n'êtes plus connecté et que les liens d'inscription et de connexion s'affichent à nouveau.
Tout fonctionne parfaitement, mais j'ai remarqué que lorsqu'un utilisateur est connecté et visite la page d'inscription à l'adresse http://127.0.0.1:8000/users/sign_up/, il a toujours accès au formulaire d'inscription. Idéalement, une fois qu'un utilisateur est connecté, il ne devrait pas pouvoir accéder à la page d'inscription.
Guide to Building a Complete Blog App with Django using TDD Methodology and PostgreSQL (Part  Secure User Authentication
Ce comportement peut introduire plusieurs vulnérabilités de sécurité dans notre projet. Pour résoudre ce problème, nous devons mettre à jour SignUpView pour rediriger tout utilisateur connecté vers la page d'accueil.
Mais d'abord, mettons à jour notre LoginTest pour ajouter un nouveau test qui couvre le scénario. Donc, dans le fichier users/tests/test_views.py, ajoutez ce code.

# users/forms.py
from django.contrib.auth import AuthenticationForm

class LoginForm(AuthenticationForm):


Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Maintenant, nous pouvons mettre à jour notre SignUpView

# users/tests/test_forms.py

#   --- other code

class LoginFormTest(TestCase):
  def setUp(self):
    self.user = User.objects.create_user(
      full_name= 'Tester User',
      email= 'tester@gmail.com',
      bio= 'new bio for tester',
      password= 'password12345'
    )

  def test_valid_credentials(self):
    """
    With valid credentials, the form should be valid
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': 'password12345',
      'remember_me': False
    }

    form = LoginForm(data = credentials)
    self.assertTrue(form.is_valid())

  def test_wrong_credentials(self):
    """
    With wrong credentials, the form should raise Invalid email or password error
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': 'wrongpassword',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertIn('Invalid email or password', str(form.errors['__all__']))

  def test_credentials_with_empty_email(self):
    """
    Should raise an error when the email field is empty
    """
    credentials = {
      'email': '',
      'password': 'password12345',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertFalse(form.is_valid())
    self.assertIn('This field is required', str(form.errors['email']))

  def test_credentials_with_empty_password(self):
    """
    Should raise error when the password field is empty
    """
    credentials = {
      'email': 'tester@gmail.com',
      'password': '',
      'remember_me': False
    }
    form = LoginForm(data = credentials)
    self.assertFalse(form.is_valid())
    self.assertIn('This field is required', str(form.errors['password']))
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans le code ci-dessus, nous remplaçons la méthode dispatch() de notre SignUpView pour rediriger tout utilisateur déjà connecté et essayant d'accéder à la page d'inscription. Cette redirection utilisera le LOGIN_REDIRECT_URL défini dans notre fichier settings.py, qui dans ce cas pointe vers la page d'accueil.
D'accord! Encore une fois, effectuons tous nos tests pour confirmer que nos mises à jour fonctionnent comme prévu

# users/forms.py

# -- other code
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm # new line
from django.contrib.auth import get_user_model, authenticate # new line


# --- other code

class LoginForm(AuthenticationForm):
  email = forms.EmailField(
    required=True,
    widget=forms.EmailInput(attrs={'placeholder': 'Email','class': 'form-control',})
  )
  password = forms.CharField(
    required=True,
    widget=forms.PasswordInput(attrs={
                                'placeholder': 'Password',
                                'class': 'form-control',
                                'data-toggle': 'password',
                                'id': 'password',
                                'name': 'password',
                                })
  )
  remember_me = forms.BooleanField(required=False)

  def __init__(self, *args, **kwargs):
    super(LoginForm, self).__init__(*args, **kwargs)
    # Remove username field

    if 'username' in self.fields:
      del self.fields['username']

  def clean(self):
    email = self.cleaned_data.get('email')
    password = self.cleaned_data.get('password')

    # Authenticate using email and password
    if email and password:
      self.user_cache = authenticate(self.request, email=email, password=password)
      if self.user_cache is None:
        raise forms.ValidationError("Invalid email or password")
      else:
        self.confirm_login_allowed(self.user_cache)
    return self.cleaned_data

  class Meta:
    model = User
    fields = ('email', 'password', 'remember_me')
Copier après la connexion
Copier après la connexion
Copier après la connexion

Je sais qu'il y a encore beaucoup à accomplir, mais prenons un moment pour apprécier ce que nous avons accompli jusqu'à présent. Ensemble, nous avons configuré notre environnement de projet, connecté une base de données PostgreSQL et mis en œuvre un système sécurisé d'enregistrement et de connexion des utilisateurs pour notre application de blog Django. Dans la partie suivante, nous aborderons la création d'une page de profil utilisateur, permettant aux utilisateurs de modifier leurs informations et de réinitialiser leur mot de passe ! Restez à l'écoute pour des développements plus passionnants alors que nous poursuivons notre voyage avec l'application de blog Django !

Vos commentaires sont toujours appréciés. Veuillez partager vos réflexions, questions ou suggestions dans les commentaires ci-dessous. N'oubliez pas d'aimer, de laisser un commentaire et de vous abonner pour rester informé des derniers développements !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!