Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

DRFにてログイン認証。authenticateの正常系がうまく返らない

解決したいこと

新規登録画面、ログイン、ログアウトをDjango Rest Framework(DRF)で実装していますが、ログインの際に authenticate メソッドが正しく機能しない問題が発生しています。正しいユーザー名とパスワードを入力しても、None が返されてしまいます。

発生している問題・エラー

シリアライザの中で authenticate(username=username, password=password) に正しい値が渡されているにもかかわらず、None が返されてしまいます。
authenticate(username=username, password=password)には正しいパスワードとユーザーを入れているにもかかわらず、Noneが返されるのが今の問題です。
username = data.get('username')
password = data.get('password')は正しい値を取得できてます

    def validate(self, data):
        username = data.get('username')
        password = data.get('password')
        user = authenticate(username=username, password=password)
        if user is not None:
            # 認証成功
            print("認証成功:", user)
            return data
        else:
            # 認証失敗
            print("認証失敗")
            raise serializers.ValidationError('some_field は無効な値です。')

API情報

<!-- 登録 -->
curl -X POST -H "Content-Type: application/json" -d "{\"register\": {\"username\": \"exam89\", \"email\": \"user@example.com\", \"password\": \"secret_password\"}, \"other_data\": {\"birth_day\": \"1990-01-01\", \"favorite\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}" http://localhost:8000/users/register/

<!-- ログイン -->

curl -X POST -H "Content-Type: application/json" -d "{\"username\": \"exam89\", \"email\": \"user@example.com\",\"password\": \"secret_password\"}" http://localhost:8000/users/login/

ソースコード

serializer.py
import logging
# ロガーの設定
logger = logging.getLogger(__name__)

from rest_framework import serializers
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
# 例: views.py などでのパスワードの更新
from .models import UserInfo
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email', 'password']
        extra_kwargs = {'password': {'write_only': True}}
class UserInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserInfo
        fields = ('user','birth_day','favorite','created_at')
class LoginSerializer(serializers.Serializer):
    # 1.受け入れるシリアライザデータを作成する(fields)
    username = serializers.CharField(max_length=255, write_only=True)
    password = serializers.CharField(write_only=True, style={'input_type': 'password'})
    def validate(self, data):
        username = data.get('username')
        password = data.get('password')
        user = authenticate(username=username, password=password)
        if user is not None:
            # 認証成功
            print("認証成功:", user)
            return data
        else:
            # 認証失敗
            print("認証失敗")
            raise serializers.ValidationError('some_field は無効な値です。')

view.py
from rest_framework import viewsets
from rest_framework.views import APIView
from .models import UserInfo,User
from .serializer import UserInfoSerializer, UserSerializer,LoginSerializer
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from rest_framework_simplejwt.tokens import AccessToken
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import generics
from django.contrib.auth.hashers import make_password

from django.db import transaction

import logging
logger = logging.getLogger(__name__)
class UserInfoViewSet(viewsets.ModelViewSet):
    queryset = UserInfo.objects.all()
    serializer_class = UserInfoSerializer
    @transaction.atomic
    def create(self, request, *args, **kwargs):
        user_data = request.data.get('register')
        userinfo_data = request.data.get('other_data')
        user_serializer = UserSerializer(data=user_data)
        logging.debug("debug")
        if user_serializer.is_valid():
            # パスワードを変換
            user_serializer.validated_data['password'] = make_password(user_serializer.validated_data['password'])
            user = user_serializer.save()
            userinfo_data['user'] = user.id
            userinfo_serializer = UserInfoSerializer(data=userinfo_data)
            if userinfo_serializer.is_valid():
                # ここでデータを保存する
                userinfo_serializer.save()
                return Response(data=user_serializer.data, status=201)
            else:
                return Response(userinfo_serializer.data, userinfo_serializer.errors)
        else:
            return Response(user_serializer.data, user_serializer.errors)
        # else:
            # logger.error(f"UserInfoSerializer validation error: {userinfo_serializer.errors}") 

class LoginAPIView(generics.GenericAPIView):
    logging.debug("debug")
    permission_classes = [AllowAny]
    # ここにシリアライザを定義しておくと、以下のように、シリアライザを簡単に呼び出す
    serializer_class = LoginSerializer
    @transaction.atomic
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        print("ログイン:serializer")
        if serializer.is_valid(raise_exception=True):
            user = User.objects.get(username=serializer.validated_data["username"])
            return Response({'detail': "ログインが成功しました。", 'error': 0})
            # return Response({'detail': "ログインが成功しました。", 'error': 0, 'token': token.token, 'user_id': user_id})
        return Response({'error': 1}, status=HTTP_400_BAD_REQUEST)
url.py
import logging
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from rest_framework.authtoken.views import obtain_auth_token
from sayhellotobikeAPI.views import UserInfoViewSet, LoginAPIView

# DefaultRouter クラスのインスタンスを代入
defaultRouter = routers.DefaultRouter()
# userInfo/ にUserInfoViewSetをルーティングする
defaultRouter.register('register', UserInfoViewSet, basename='register')

# UserLoginView
urlpatterns = [
    path('admin/', admin.site.urls),
    # ログイン用のエンドポイントを追加
    path('users/login/', LoginAPIView.as_view(), name='login'),
    # defaultRouter をinclude する
    path('users/', include(defaultRouter.urls)),
]
model.py
from django.db import models
from django.contrib.auth.models import User

class UserInfo(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    birth_day = models.DateField(verbose_name='生年月日')  
    favorite = models.CharField(verbose_name='お気に入りの', max_length=100, default='特になし')  # favorite フィールドを追加
    created_at = models.DateTimeField(verbose_name='作成日時', auto_now_add=True)

    def __str__(self):
        return self.user.username

自分で試したこと

authincate関数はこちらで調べました。
https://docs.djangoproject.com/ja/2.2/_modules/django/contrib/auth/#authenticate
また、ヘイブンのままパスワードを保存していたので、ハッシュ化して保存しました

備考

私もまだまだなエンジニアですが、皆様公式ドキュメントを閲覧するとき、どのようなことを意識していますでしょうか?
ライブラリの場合は記述している内容だけではなく、ライブラリのソースコードを見るようにしてはいますが、、

ご回答いただけたら幸いです。よろしくお願いいたします。

0

No Answers yet.

Your answer might help someone💌