본문 바로가기

[내일배움캠프]스파르타코딩클럽 AI 웹개발/Today I Learned

[TIL] 이메일 인증(2) - 로그인

기존에는 비활성화 계정이 로그인을 시도하면 즉각적으로 계정이 활성화되는 동시에 로그인이 되었지만

이메일 인증을 통해 계정을 활성화 한 뒤에 로그인을 할 수 있도록 코드를 변경하였다

 

 

1.  기존 코드

class UserSigninAPIView(APIView):
    def post(self, request):
        email = request.data.get("email")
        password = request.data.get("password")

        user = User.objects.filter(email=email)
        message = False
        if user and user[0].is_active == False:
            user[0].is_active = True
            user[0].deactivate_time = None
            user[0].save()
            message = "계정이 활성화되었습니다."

        user = authenticate(email=email, password=password)

        if not user:
            return Response(
                {"error": "이메일 혹은 패스워드가 일치하지 않습니다."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        refresh = RefreshToken.for_user(user)
        data = {
            "refresh": str(refresh),
            "access": str(refresh.access_token),
        }

        user = get_user_model().objects.get(email=email)
        data["id"] = user.id
        data["email"] = user.email
        data["nickname"] = user.nickname
        data["gender"] = user.gender
        data["age"] = user.age
        data["bio"] = user.bio

        if message:
            data["message"] = message

        return Response(
            data=data,
            status=status.HTTP_200_OK,
        )

 

계정이 있는지 확인하고, 계정이 존재하면서 비활성화 계정인 경우 계정을 활성화 한 뒤에 로그인을 시도한다

계정이 없는 경우에는 에러메세지를 반환한다

 

로그인이 된 후에는 토큰과 유저의 정보를 전달해준다

 

 

2.  문제

 

기존의 코드를 그대로 사용하는 경우 회원가입 후에 이메일 인증을 하지 않고 로그인하더라도 계정이 바로 활성화가 되는 문제가 있다

따라서 비활성화 계정이 로그인을 시도하는 경우도 마찬가지로 이메일 인증을 통해 계정을 활성화 시킨 후에 로그인을 하여 서비스를 이용할 수있도록 변경하는 것이 필요했다

 

 

3. 변경된 코드

 

기존에는 로그인을 할 때 serializer를 사용하지 않고 authenticate를 사용하여 로그인을 한 후에 토큰을 전달해 주었지만,

이메일 인증을 위해 시리얼라이저를 생성하고 시리얼라이저를 거쳐 이메일을 전송하도록 변경하였다

 

class UserSigninSerializer(serializers.ModelSerializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ["email", "password"]

    def validate(self, attrs):
        email = attrs.get("email")
        password = attrs.get("password")

        # 사용자가 존재하는지 확인
        user = User.objects.filter(email=email).first()
        if user is None:
            raise serializers.ValidationError(
                "이메일 혹은 패스워드가 일치하지 않습니다."
            )

        # 비활성화된 계정일 경우
        if not user.is_active:
            self.send_activation_email(user)
            raise serializers.ValidationError(
                "계정이 비활성화 상태입니다. 이메일 인증을 통해 계정을 활성화해주세요."
            )

        # 사용자 인증
        if not user.check_password(password):
            raise serializers.ValidationError(
                "이메일 혹은 패스워드가 일치하지 않습니다."
            )

        return attrs

    def send_activation_email(self, user):

        # 이메일 전송을 위한 토큰 생성
        token_generator = PasswordResetTokenGenerator()
        token = token_generator.make_token(user)
        uid = urlsafe_base64_encode(force_bytes(user.pk))

        subject = "Activate Your Account"
        message = render_to_string(
            "accounts/account_active_email.html",  # 이메일 템플릿 경로
            {
                "user": user,
                "domain": "127.0.0.1:8000",  # 도메인 설정
                "uid": uid,  # 사용자 ID 인코딩
                "token": token,  # 활성화 토큰 생성
            },
        )

        send_mail(
            subject,
            message,
            settings.DEFAULT_FROM_EMAIL,  # 발신자 이메일
            [user.email],  # 수신자 이메일
            fail_silently=False,
        )

 

 

시리얼라이저를 생성한 후에 view로 돌아가 signinAPIView도 변경해주었다

 

class UserSigninAPIView(APIView):
    def post(self, request):
        email = request.data.get("email")
        password = request.data.get("password")
        serializer = UserSigninSerializer(data=request.data)
        if serializer.is_valid():
            user = authenticate(email=email, password=password)
            refresh = RefreshToken.for_user(user)
            data = {
                "refresh": str(refresh),
                "access": str(refresh.access_token),
            }
            signin_user = get_user_model().objects.get(email=email)
            data["id"] = signin_user.id
            data["email"] = signin_user.email
            data["nickname"] = signin_user.nickname
            data["gender"] = signin_user.gender
            data["age"] = signin_user.age
            data["bio"] = signin_user.bio

            return Response(data=data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)