user3521180
user3521180

Reputation: 1130

why django resframework login view not able to authenticate user?

I am developing an OTP based authentication model. below are the back-end and front-end logic

serializers.py

class LoginSerializer(serializers.Serializer):
email = serializers.EmailField()
otp = serializers.CharField()

def validate(self, data):
    email = data.get('email')
    otp = data.get('otp')

    # Logging the initial validation step
    api_log(msg="Starting validation")

    # Check if email exists
    try:
        user = User.objects.get(email=email)
    except User.DoesNotExist:
        raise serializers.ValidationError(
            {
                "email": "Email does not exist."
            }
        )

    if user.otp != otp:
        raise serializers.ValidationError(
            {
                "otp": "OTP is invalid or expired."
            }
        )

    if User.otp_expiry and User.otp_expiry < timezone.now():
        raise serializers.ValidationError(
            {
                "otp": "OTP is expired."
            }
        )

    # Attach user to validated data
    data['user'] = User
    return data

views.py

class LoginView(KnoxLoginView):
    # @csrf_exempt
    def post(self, request, *args, **kwargs):
        serializer = LoginSerializer(data=request.data)
        api_log(msg=f"login view serializers : {serializer}")

        if serializer.is_valid():
            user = serializer.validated_data['user']
            api_log(msg=f"login view USER : {user}")

            # Invalidate the OTP
            user.otp = None
            user.otp_expiry = None
            user.save()

            # Create auth token
            _, token = AuthToken.objects.create(user)
            api_log(msg=f"login view TOKEN : {token}")

            return Response({'token': token}, status=status.HTTP_200_OK)
        else:
            return Response({'error': serializer.errors}, status=status.HTTP_400_BAD_REQUEST)

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
</head>
<body>
<form id="login-form">
    {% csrf_token %}
    <div class="form-group">
        <h1>Login</h1>
        <p>Please enter your email and OTP to login.</p>
        <hr>

        <label for="email"><b>Email</b></label>
        <input type="text" placeholder="Enter Email" name="email" id="email" required><br>
        <label for="otp"><b>OTP</b></label>
        <input type="text" placeholder="Enter OTP" name="otp" id="otp" required>
        <hr>
        <br></br>

        <button type="submit" class="loginbtn" id="login-btn">Login</button>

        <div id="login-response"></div>
    </div>
</form>

<script>
  function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
      const cookies = document.cookie.split(';');
      for (let i = 0; i < cookies.length; i++) {
        const cookie = cookies[i].trim();
        if (cookie.substring(0, name.length + 1) === (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  }

  const csrftoken = getCookie('csrftoken');

  document.getElementById('login-btn').addEventListener('click', function(event) {
    event.preventDefault();

    const email = document.getElementById('email').value;
    const otp = document.getElementById('otp').value;

    fetch('{% url "login" %}', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRFToken': csrftoken
      },
      body: JSON.stringify({ email: email, otp: otp })
    })
    .then(response => {
      if (!response.ok) {
        throw new Error(response.statusText);
      }
      return response.json();
    })
    .then(data => {
      if (data.token) {
        window.location.href = '{% url "home" %}';
      } else {
        document.getElementById('login-response').innerHTML = `Error: ${data.error}`;
      }
    })
    .catch(error => {
      document.getElementById('login-response').innerHTML = `Error: ${error.message}`;
    });
  });
</script>
</body>
</html>

when I am calling the POST login api in postman,

 http://127.0.0.1:8000/auth/login/

I am getting below error

{
    "detail": "Authentication credentials were not provided."
}

Since I am also using knox token authentication, so I believe that I need to pass the token that is generated in the response from "inspect" page. I see something like below

csrftoken=W64v4ufsbifnajoUMyFp64S3aemXfCEj

I used this in the postman's headers

csrftoken:W64v4ufsbifnajoUMyFp64S3aemXfCEj
Content-Type:application/json

I see below curl in postman

curl --location 'http://127.0.0.1:8000/auth/login/'
--header 'csrftoken: W64v4ufsbifnajoUMyFp64S3aemXfCEj'
--header 'Content-Type: application/json'
--data-raw '{ "email": "[email protected]", "otp": "196345" }'

I receives below error in my IDE console

Forbidden: /auth/login/
[14/Jun/2024 14:29:40] "POST /auth/login/ HTTP/1.1" 403 58

Upvotes: 0

Views: 36

Answers (0)

Related Questions