无法在Apache2/Ubuntu服务器中使用用户的令牌对Django用户进行身份验证。

huangapple go评论68阅读模式
英文:

Cannot authenticate a Django user using his token in a Apache2/Ubuntu server

问题

I have reviewed your code and the issue you are facing with token authentication. It seems like you have followed the tutorial correctly, but there might be a couple of things to check:

  1. Token Creation: When you create a superuser using the management command, make sure that it indeed creates a token for that user. You mentioned that it shows the same token as when creating the superuser. This might indicate that the token creation part is not working as expected. Double-check the Token.objects.create(user=user) line in your management command to ensure it's creating a unique token for each user.

  2. Token Authorization Header: Ensure that you are passing the token correctly in the Authorization header when making API requests. The format should be: Authorization: Token <your-token>.

  3. Token Authentication: Make sure that the TokenAuthentication class is included in your Django REST Framework settings. You have it configured correctly in your REST_FRAMEWORK settings, so it should be enabled.

  4. URL Configuration: Confirm that you are accessing the correct URL and that the CurrentUserView view is indeed protected by token authentication. You have configured IsAuthenticated permission correctly for that view.

  5. Debugging: You can add some debugging statements to your LoginView and CurrentUserView to see if the token is being correctly passed and authenticated. You can log the request.data in the LoginView to ensure that email and password are being received correctly.

  6. Testing with Other Tools: Since you mentioned that Postman also fails, it's possible that there is an issue with your Django setup. Try creating a new test user and obtaining a new token using Postman to see if the issue persists.

  7. Check for Any Middleware Interference: Ensure that there are no custom middleware or decorators in your project that might interfere with token authentication.

  8. Django Version Compatibility: Ensure that the Django version you are using is compatible with the version of Django REST Framework and the token authentication package you are using.

By carefully checking these points, you should be able to identify the issue and resolve the "Authentication credentials were not provided" error. If the problem persists, consider providing more specific details about your Django and Django REST Framework versions, as well as any custom code you may have that could be affecting authentication.

英文:

I am creating a Django rest framework API to interact with an Android app.

I have opened the following endpoints:

from django.urls import path, include
from .views import UserViewSet, UserProfileViewSet, CurrentUserView,LoginView 

urlpatterns = [
    path(&#39;usuarios/&#39;, UserViewSet.as_view(), name=&#39;usuarios&#39;),
    path(&#39;usuarios-perfil/&#39;, UserProfileViewSet.as_view(), name=&#39;usuarios-perfil&#39;),
    path(&#39;usuario-actual/&#39;, CurrentUserView.as_view(), name=&#39;usuario-actual&#39;),
    path(&#39;login/&#39;, LoginView.as_view(), name=&#39;login&#39;),
]

My views are these ones:

from rest_framework import generics
from django.contrib.auth.models import User
from .models import UserProfile
from .serializers import UserSerializer, UserProfileSerializer
from rest_framework.permissions import IsAuthenticated
from django.contrib.auth import get_user_model
from django.contrib.auth import authenticate
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
import logging

logger = logging.getLogger(__name__)

class UserViewSet(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

class UserProfileViewSet(generics.ListCreateAPIView):
    queryset = UserProfile.objects.all()
    serializer_class = UserProfileSerializer

class CurrentUserView(generics.RetrieveAPIView):
    permission_classes = (IsAuthenticated,) 
    serializer_class = UserSerializer
    def get_object(self):
        logger.info(self.request.META)
        logger.debug(f&quot;CurrentUserView.get_object called for user {self.request.user}&quot;)
        return self.request.user
def authenticate(email=None, password=None):
    UserModel = get_user_model()
    try:
        user = UserModel.objects.get(email=email)
    except UserModel.DoesNotExist:
        return None

    if user.check_password(password):
        return user

# En tu LoginView
class LoginView(APIView):
    def post(self, request, format=None):
        user = authenticate(email=request.data.get(&#39;email&#39;), password=request.data.get(&#39;password&#39;))
        if user is not None:
            token, created = Token.objects.get_or_create(user=user)
            return Response({&#39;token&#39;: token.key})
        else:
            return Response(status=401)

My models:

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    is_premium = models.BooleanField(default=False)

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

My serializers:

from rest_framework import serializers
from django.contrib.auth.models import User
from .models import UserProfile

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = [&#39;username&#39;, &#39;is_staff&#39;]

class UserProfileSerializer(serializers.ModelSerializer):
    user = UserSerializer()

    class Meta:
        model = UserProfile
        fields = [&#39;user&#39;, &#39;is_premium&#39;]

And this is my settings.py:

&quot;&quot;&quot;
Django settings for football_quiz_and_guide project.

Generated by &#39;django-admin startproject&#39; using Django 4.2.3.

For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
&quot;&quot;&quot;

from pathlib import Path
import os

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = &#39;my-secret-key&#39;

DEBUG = True

ALLOWED_HOSTS = [&#39;my-domain.com&#39;,&#39;my-VM-instance-IP&#39;]

# Configuraciones de seguridad
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
#SECURE_SSL_REDIRECT = True

# Application definition
INSTALLED_APPS = [
    &#39;django.contrib.admin&#39;,
    &#39;django.contrib.auth&#39;,
    &#39;django.contrib.contenttypes&#39;,
    &#39;django.contrib.sessions&#39;,
    &#39;django.contrib.messages&#39;,
    &#39;django.contrib.staticfiles&#39;,
    &#39;api_es&#39;,
    &#39;rest_framework&#39;, 
    &#39;rest_framework.authtoken&#39;,
]

MIDDLEWARE = [
    &#39;django.middleware.security.SecurityMiddleware&#39;,
    &#39;django.contrib.sessions.middleware.SessionMiddleware&#39;,
    &#39;django.middleware.common.CommonMiddleware&#39;,
    &#39;django.middleware.csrf.CsrfViewMiddleware&#39;,
    &#39;django.contrib.auth.middleware.AuthenticationMiddleware&#39;,
    &#39;django.contrib.messages.middleware.MessageMiddleware&#39;,
    &#39;django.middleware.clickjacking.XFrameOptionsMiddleware&#39;,
]

ROOT_URLCONF = &#39;football_quiz_and_guide.urls&#39;

TEMPLATES = [
    {
        &#39;BACKEND&#39;: &#39;django.template.backends.django.DjangoTemplates&#39;,
        &#39;DIRS&#39;: [],
        &#39;APP_DIRS&#39;: True,
        &#39;OPTIONS&#39;: {
            &#39;context_processors&#39;: [
                &#39;django.template.context_processors.debug&#39;,
                &#39;django.template.context_processors.request&#39;,
                &#39;django.contrib.auth.context_processors.auth&#39;,
                &#39;django.contrib.messages.context_processors.messages&#39;,
            ],
        },
    },
]

WSGI_APPLICATION = &#39;football_quiz_and_guide.wsgi.application&#39;


# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {
    &#39;default&#39;: {
        &#39;ENGINE&#39;: &#39;django.db.backends.mysql&#39;,
        &#39;NAME&#39;: &#39;apifutbol_db&#39;,
        &#39;USER&#39;: &#39;quiz-and-guide&#39;,
        &#39;PASSWORD&#39;: &#39;AdGj2727&#39;,
        &#39;HOST&#39;: &#39;34.175.80.143&#39;,
        &#39;PORT&#39;: &#39;3306&#39;,
    }
}
#DATABASES = {
#    &#39;default&#39;: {
#        &#39;ENGINE&#39;: &#39;django.db.backends.mysql&#39;,
#        &#39;NAME&#39;: &#39;apifutbol_db&#39;,
#        &#39;USER&#39;: &#39;quizandguide&#39;,
#        &#39;PASSWORD&#39;: &#39;AdGj2727&#39;,
#        &#39;HOST&#39;: &#39;localhost&#39;,   # Or an IP Address that your DB is hosted on
#        &#39;PORT&#39;: &#39;3306&#39;,
#    }
#}
#DATABASES = {
#    &#39;default&#39;: {
#        &#39;ENGINE&#39;: &#39;django.db.backends.sqlite3&#39;,
#        &#39;NAME&#39;: BASE_DIR / &#39;db.sqlite3&#39;,
#    }
#}
REST_FRAMEWORK = {
    &#39;DEFAULT_AUTHENTICATION_CLASSES&#39;: [
        &#39;rest_framework.authentication.TokenAuthentication&#39;,
    ]
}

LOGGING = {
    &#39;version&#39;: 1,
    &#39;disable_existing_loggers&#39;: False,
    &#39;handlers&#39;: {
        &#39;file&#39;: {
            &#39;level&#39;: &#39;DEBUG&#39;,
            &#39;class&#39;: &#39;logging.FileHandler&#39;,
            &#39;filename&#39;: &#39;/var/log/apache2/debug.log&#39;,
        },
    },
    &#39;root&#39;: {
        &#39;handlers&#39;: [&#39;file&#39;],
        &#39;level&#39;: &#39;DEBUG&#39;,
    },
}





# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        &#39;NAME&#39;: &#39;django.contrib.auth.password_validation.UserAttributeSimilarityValidator&#39;,
    },
    {
        &#39;NAME&#39;: &#39;django.contrib.auth.password_validation.MinimumLengthValidator&#39;,
    },
    {
        &#39;NAME&#39;: &#39;django.contrib.auth.password_validation.CommonPasswordValidator&#39;,
    },
    {
        &#39;NAME&#39;: &#39;django.contrib.auth.password_validation.NumericPasswordValidator&#39;,
    },
]

# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = &#39;es-es&#39;

TIME_ZONE = &#39;Europe/Madrid&#39;

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = &#39;static/&#39;
STATIC_ROOT = os.path.join(BASE_DIR, &quot;static/&quot;)

# Ruta base para archivos media.
MEDIA_URL = &#39;/media/&#39;
# Ruta absoluta en el sistema de ficheros a la carpeta que va a contener los archivos que los usuarios suben.
MEDIA_ROOT = os.path.join(BASE_DIR, &#39;media&#39;)


# Media files

MEDIA_URL = &#39;/media/&#39;
MEDIA_ROOT = os.path.join(BASE_DIR, &#39;media/&#39;)

# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = &#39;django.db.models.BigAutoField&#39;

I have created my superuser with this command that also creates a Token for the user in authtoken_token table in the MySQL Database:

from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
from api_es.models import UserProfile
from rest_framework.authtoken.models import Token  # Aseg&#250;rate de que est&#225;s importando el modelo Token de aqu&#237;

class Command(BaseCommand):
    help = &#39;Crea un nuevo usuario superusuario&#39;

    def handle(self, *args, **options):
        username = &#39;lolo&#39;
        password = &#39;AdGj2727&#39;
        email = &#39;quizandguide@gmail.com&#39;

        # Crear una nueva instancia de User y guardarla
        user = User(username=username, email=email, is_active=True, is_superuser=True, is_staff=True)
        user.set_password(password)
        user.save()

        # Crear una nueva instancia de UserProfile y guardarla
        user_profile = UserProfile(user=user, is_premium=True)
        user_profile.save()

        # Crear un token para el usuario
        token = Token.objects.create(user=user)

        self.stdout.write(self.style.SUCCESS(&#39;Superusuario creado exitosamente.&#39;))

The user is created. But when I try to access to user data:

curl -H &quot;Authorization: Token &lt;my-token&gt;&quot; https://my-domain.com/es/usuario-actual/

I get:

(myenv) C:\Users\mimur\Desktop\football_quiz_and_guide\football_quiz_and_guide&gt;curl -H &quot;Authorization: Token e65905ad748d67f127929c14d3a78b9de8300c51&quot; https://football-quiz-and-guide.com/es/usuario-actual/
{&quot;detail&quot;:&quot;Las credenciales de autenticaci&#243;n no se proveyeron.&quot;}

Which means translated "Authentication credentials were not provided."

I have asked GPT4 giving it lot of info, but I don't find a solution. I have followed this tutorial step by step. When I create a token for user lolo it doesn't create a new one. It shows the same Token created while creating the superuser. But the curl request fails. I have tried with Postman and it fails too.

What can be failing and what can I do?

答案1

得分: 1

最终,GPT4 可以意识到发生了什么。

在我的 /etc/apache2/sites-available/000-default.conf 文件中,我需要添加以下行以允许头部信息:

WSGIPassAuthorization On

然后我可以通过 curl 请求或 Android 应用程序访问我的用户数据视图。

英文:

Finnaly GPT4 could realize what was hapenning.

In my /etc/apache2/sites-available/000-default.conf file I needed to allow headers with the line:

WSGIPassAuthorization On

Then I could access to the view of my user data from a curl petition or the Android app.

huangapple
  • 本文由 发表于 2023年7月20日 19:48:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76729541.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定