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

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

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:

  1. from django.urls import path, include
  2. from .views import UserViewSet, UserProfileViewSet, CurrentUserView,LoginView
  3. urlpatterns = [
  4. path(&#39;usuarios/&#39;, UserViewSet.as_view(), name=&#39;usuarios&#39;),
  5. path(&#39;usuarios-perfil/&#39;, UserProfileViewSet.as_view(), name=&#39;usuarios-perfil&#39;),
  6. path(&#39;usuario-actual/&#39;, CurrentUserView.as_view(), name=&#39;usuario-actual&#39;),
  7. path(&#39;login/&#39;, LoginView.as_view(), name=&#39;login&#39;),
  8. ]

My views are these ones:

  1. from rest_framework import generics
  2. from django.contrib.auth.models import User
  3. from .models import UserProfile
  4. from .serializers import UserSerializer, UserProfileSerializer
  5. from rest_framework.permissions import IsAuthenticated
  6. from django.contrib.auth import get_user_model
  7. from django.contrib.auth import authenticate
  8. from rest_framework.views import APIView
  9. from rest_framework.response import Response
  10. from rest_framework.authtoken.models import Token
  11. import logging
  12. logger = logging.getLogger(__name__)
  13. class UserViewSet(generics.ListCreateAPIView):
  14. queryset = User.objects.all()
  15. serializer_class = UserSerializer
  16. class UserProfileViewSet(generics.ListCreateAPIView):
  17. queryset = UserProfile.objects.all()
  18. serializer_class = UserProfileSerializer
  19. class CurrentUserView(generics.RetrieveAPIView):
  20. permission_classes = (IsAuthenticated,)
  21. serializer_class = UserSerializer
  22. def get_object(self):
  23. logger.info(self.request.META)
  24. logger.debug(f&quot;CurrentUserView.get_object called for user {self.request.user}&quot;)
  25. return self.request.user
  26. def authenticate(email=None, password=None):
  27. UserModel = get_user_model()
  28. try:
  29. user = UserModel.objects.get(email=email)
  30. except UserModel.DoesNotExist:
  31. return None
  32. if user.check_password(password):
  33. return user
  34. # En tu LoginView
  35. class LoginView(APIView):
  36. def post(self, request, format=None):
  37. user = authenticate(email=request.data.get(&#39;email&#39;), password=request.data.get(&#39;password&#39;))
  38. if user is not None:
  39. token, created = Token.objects.get_or_create(user=user)
  40. return Response({&#39;token&#39;: token.key})
  41. else:
  42. return Response(status=401)

My models:

  1. from django.db import models
  2. from django.contrib.auth.models import User
  3. class UserProfile(models.Model):
  4. user = models.OneToOneField(User, on_delete=models.CASCADE)
  5. is_premium = models.BooleanField(default=False)
  6. def __str__(self):
  7. return self.user.username

My serializers:

  1. from rest_framework import serializers
  2. from django.contrib.auth.models import User
  3. from .models import UserProfile
  4. class UserSerializer(serializers.ModelSerializer):
  5. class Meta:
  6. model = User
  7. fields = [&#39;username&#39;, &#39;is_staff&#39;]
  8. class UserProfileSerializer(serializers.ModelSerializer):
  9. user = UserSerializer()
  10. class Meta:
  11. model = UserProfile
  12. fields = [&#39;user&#39;, &#39;is_premium&#39;]

And this is my settings.py:

  1. &quot;&quot;&quot;
  2. Django settings for football_quiz_and_guide project.
  3. Generated by &#39;django-admin startproject&#39; using Django 4.2.3.
  4. For more information on this file, see
  5. https://docs.djangoproject.com/en/4.2/topics/settings/
  6. For the full list of settings and their values, see
  7. https://docs.djangoproject.com/en/4.2/ref/settings/
  8. &quot;&quot;&quot;
  9. from pathlib import Path
  10. import os
  11. BASE_DIR = Path(__file__).resolve().parent.parent
  12. SECRET_KEY = &#39;my-secret-key&#39;
  13. DEBUG = True
  14. ALLOWED_HOSTS = [&#39;my-domain.com&#39;,&#39;my-VM-instance-IP&#39;]
  15. # Configuraciones de seguridad
  16. CSRF_COOKIE_SECURE = True
  17. SESSION_COOKIE_SECURE = True
  18. SECURE_HSTS_SECONDS = 31536000
  19. SECURE_HSTS_INCLUDE_SUBDOMAINS = True
  20. SECURE_HSTS_PRELOAD = True
  21. #SECURE_SSL_REDIRECT = True
  22. # Application definition
  23. INSTALLED_APPS = [
  24. &#39;django.contrib.admin&#39;,
  25. &#39;django.contrib.auth&#39;,
  26. &#39;django.contrib.contenttypes&#39;,
  27. &#39;django.contrib.sessions&#39;,
  28. &#39;django.contrib.messages&#39;,
  29. &#39;django.contrib.staticfiles&#39;,
  30. &#39;api_es&#39;,
  31. &#39;rest_framework&#39;,
  32. &#39;rest_framework.authtoken&#39;,
  33. ]
  34. MIDDLEWARE = [
  35. &#39;django.middleware.security.SecurityMiddleware&#39;,
  36. &#39;django.contrib.sessions.middleware.SessionMiddleware&#39;,
  37. &#39;django.middleware.common.CommonMiddleware&#39;,
  38. &#39;django.middleware.csrf.CsrfViewMiddleware&#39;,
  39. &#39;django.contrib.auth.middleware.AuthenticationMiddleware&#39;,
  40. &#39;django.contrib.messages.middleware.MessageMiddleware&#39;,
  41. &#39;django.middleware.clickjacking.XFrameOptionsMiddleware&#39;,
  42. ]
  43. ROOT_URLCONF = &#39;football_quiz_and_guide.urls&#39;
  44. TEMPLATES = [
  45. {
  46. &#39;BACKEND&#39;: &#39;django.template.backends.django.DjangoTemplates&#39;,
  47. &#39;DIRS&#39;: [],
  48. &#39;APP_DIRS&#39;: True,
  49. &#39;OPTIONS&#39;: {
  50. &#39;context_processors&#39;: [
  51. &#39;django.template.context_processors.debug&#39;,
  52. &#39;django.template.context_processors.request&#39;,
  53. &#39;django.contrib.auth.context_processors.auth&#39;,
  54. &#39;django.contrib.messages.context_processors.messages&#39;,
  55. ],
  56. },
  57. },
  58. ]
  59. WSGI_APPLICATION = &#39;football_quiz_and_guide.wsgi.application&#39;
  60. # Database
  61. # https://docs.djangoproject.com/en/4.2/ref/settings/#databases
  62. DATABASES = {
  63. &#39;default&#39;: {
  64. &#39;ENGINE&#39;: &#39;django.db.backends.mysql&#39;,
  65. &#39;NAME&#39;: &#39;apifutbol_db&#39;,
  66. &#39;USER&#39;: &#39;quiz-and-guide&#39;,
  67. &#39;PASSWORD&#39;: &#39;AdGj2727&#39;,
  68. &#39;HOST&#39;: &#39;34.175.80.143&#39;,
  69. &#39;PORT&#39;: &#39;3306&#39;,
  70. }
  71. }
  72. #DATABASES = {
  73. # &#39;default&#39;: {
  74. # &#39;ENGINE&#39;: &#39;django.db.backends.mysql&#39;,
  75. # &#39;NAME&#39;: &#39;apifutbol_db&#39;,
  76. # &#39;USER&#39;: &#39;quizandguide&#39;,
  77. # &#39;PASSWORD&#39;: &#39;AdGj2727&#39;,
  78. # &#39;HOST&#39;: &#39;localhost&#39;, # Or an IP Address that your DB is hosted on
  79. # &#39;PORT&#39;: &#39;3306&#39;,
  80. # }
  81. #}
  82. #DATABASES = {
  83. # &#39;default&#39;: {
  84. # &#39;ENGINE&#39;: &#39;django.db.backends.sqlite3&#39;,
  85. # &#39;NAME&#39;: BASE_DIR / &#39;db.sqlite3&#39;,
  86. # }
  87. #}
  88. REST_FRAMEWORK = {
  89. &#39;DEFAULT_AUTHENTICATION_CLASSES&#39;: [
  90. &#39;rest_framework.authentication.TokenAuthentication&#39;,
  91. ]
  92. }
  93. LOGGING = {
  94. &#39;version&#39;: 1,
  95. &#39;disable_existing_loggers&#39;: False,
  96. &#39;handlers&#39;: {
  97. &#39;file&#39;: {
  98. &#39;level&#39;: &#39;DEBUG&#39;,
  99. &#39;class&#39;: &#39;logging.FileHandler&#39;,
  100. &#39;filename&#39;: &#39;/var/log/apache2/debug.log&#39;,
  101. },
  102. },
  103. &#39;root&#39;: {
  104. &#39;handlers&#39;: [&#39;file&#39;],
  105. &#39;level&#39;: &#39;DEBUG&#39;,
  106. },
  107. }
  108. # Password validation
  109. # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
  110. AUTH_PASSWORD_VALIDATORS = [
  111. {
  112. &#39;NAME&#39;: &#39;django.contrib.auth.password_validation.UserAttributeSimilarityValidator&#39;,
  113. },
  114. {
  115. &#39;NAME&#39;: &#39;django.contrib.auth.password_validation.MinimumLengthValidator&#39;,
  116. },
  117. {
  118. &#39;NAME&#39;: &#39;django.contrib.auth.password_validation.CommonPasswordValidator&#39;,
  119. },
  120. {
  121. &#39;NAME&#39;: &#39;django.contrib.auth.password_validation.NumericPasswordValidator&#39;,
  122. },
  123. ]
  124. # Internationalization
  125. # https://docs.djangoproject.com/en/4.2/topics/i18n/
  126. LANGUAGE_CODE = &#39;es-es&#39;
  127. TIME_ZONE = &#39;Europe/Madrid&#39;
  128. USE_I18N = True
  129. USE_TZ = True
  130. # Static files (CSS, JavaScript, Images)
  131. # https://docs.djangoproject.com/en/4.2/howto/static-files/
  132. STATIC_URL = &#39;static/&#39;
  133. STATIC_ROOT = os.path.join(BASE_DIR, &quot;static/&quot;)
  134. # Ruta base para archivos media.
  135. MEDIA_URL = &#39;/media/&#39;
  136. # Ruta absoluta en el sistema de ficheros a la carpeta que va a contener los archivos que los usuarios suben.
  137. MEDIA_ROOT = os.path.join(BASE_DIR, &#39;media&#39;)
  138. # Media files
  139. MEDIA_URL = &#39;/media/&#39;
  140. MEDIA_ROOT = os.path.join(BASE_DIR, &#39;media/&#39;)
  141. # Default primary key field type
  142. # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
  143. 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:

  1. from django.core.management.base import BaseCommand
  2. from django.contrib.auth.models import User
  3. from api_es.models import UserProfile
  4. from rest_framework.authtoken.models import Token # Aseg&#250;rate de que est&#225;s importando el modelo Token de aqu&#237;
  5. class Command(BaseCommand):
  6. help = &#39;Crea un nuevo usuario superusuario&#39;
  7. def handle(self, *args, **options):
  8. username = &#39;lolo&#39;
  9. password = &#39;AdGj2727&#39;
  10. email = &#39;quizandguide@gmail.com&#39;
  11. # Crear una nueva instancia de User y guardarla
  12. user = User(username=username, email=email, is_active=True, is_superuser=True, is_staff=True)
  13. user.set_password(password)
  14. user.save()
  15. # Crear una nueva instancia de UserProfile y guardarla
  16. user_profile = UserProfile(user=user, is_premium=True)
  17. user_profile.save()
  18. # Crear un token para el usuario
  19. token = Token.objects.create(user=user)
  20. 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 文件中,我需要添加以下行以允许头部信息:

  1. 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:

  1. 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:

确定