英文:
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:
-
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. -
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>
. -
Token Authentication: Make sure that the
TokenAuthentication
class is included in your Django REST Framework settings. You have it configured correctly in yourREST_FRAMEWORK
settings, so it should be enabled. -
URL Configuration: Confirm that you are accessing the correct URL and that the
CurrentUserView
view is indeed protected by token authentication. You have configuredIsAuthenticated
permission correctly for that view. -
Debugging: You can add some debugging statements to your
LoginView
andCurrentUserView
to see if the token is being correctly passed and authenticated. You can log therequest.data
in theLoginView
to ensure that email and password are being received correctly. -
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.
-
Check for Any Middleware Interference: Ensure that there are no custom middleware or decorators in your project that might interfere with token authentication.
-
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('usuarios/', UserViewSet.as_view(), name='usuarios'),
path('usuarios-perfil/', UserProfileViewSet.as_view(), name='usuarios-perfil'),
path('usuario-actual/', CurrentUserView.as_view(), name='usuario-actual'),
path('login/', LoginView.as_view(), name='login'),
]
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"CurrentUserView.get_object called for user {self.request.user}")
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('email'), password=request.data.get('password'))
if user is not None:
token, created = Token.objects.get_or_create(user=user)
return Response({'token': 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 = ['username', 'is_staff']
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = UserProfile
fields = ['user', 'is_premium']
And this is my settings.py:
"""
Django settings for football_quiz_and_guide project.
Generated by 'django-admin startproject' 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/
"""
from pathlib import Path
import os
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'my-secret-key'
DEBUG = True
ALLOWED_HOSTS = ['my-domain.com','my-VM-instance-IP']
# 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 = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'api_es',
'rest_framework',
'rest_framework.authtoken',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'football_quiz_and_guide.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'football_quiz_and_guide.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'apifutbol_db',
'USER': 'quiz-and-guide',
'PASSWORD': 'AdGj2727',
'HOST': '34.175.80.143',
'PORT': '3306',
}
}
#DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.mysql',
# 'NAME': 'apifutbol_db',
# 'USER': 'quizandguide',
# 'PASSWORD': 'AdGj2727',
# 'HOST': 'localhost', # Or an IP Address that your DB is hosted on
# 'PORT': '3306',
# }
#}
#DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
# }
#}
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': '/var/log/apache2/debug.log',
},
},
'root': {
'handlers': ['file'],
'level': 'DEBUG',
},
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = 'es-es'
TIME_ZONE = 'Europe/Madrid'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
# Ruta base para archivos media.
MEDIA_URL = '/media/'
# 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, 'media')
# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
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úrate de que estás importando el modelo Token de aquí
class Command(BaseCommand):
help = 'Crea un nuevo usuario superusuario'
def handle(self, *args, **options):
username = 'lolo'
password = 'AdGj2727'
email = 'quizandguide@gmail.com'
# 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('Superusuario creado exitosamente.'))
The user is created. But when I try to access to user data:
curl -H "Authorization: Token <my-token>" https://my-domain.com/es/usuario-actual/
I get:
(myenv) C:\Users\mimur\Desktop\football_quiz_and_guide\football_quiz_and_guide>curl -H "Authorization: Token e65905ad748d67f127929c14d3a78b9de8300c51" https://football-quiz-and-guide.com/es/usuario-actual/
{"detail":"Las credenciales de autenticación no se proveyeron."}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论