Анонимный пользователь обнаружен при доступе к rest-api с помощью simplejwt
Я могу получить доступ и обновить токен с помощью SimpleJWT. У меня есть собственный декоратор, который пытается определить тип пользователя из профиля пользователя. Код здесь не работает, потому что не может найти аутентифицированного пользователя.
Я неоднократно пытался получить пользователя через режим отладки в VS Code, но безуспешно.
Вот мой settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken', # Add this line
'rest_auth', # Add this line
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount', # we will not be using this but not keeping this entry results in error while deleting user. A known issue https://github.com/Tivix/django-rest-auth/issues/412
'crispy_forms',
'users',
]
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',
]
AUTH_USER_MODEL = 'users.User'
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
#'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}
REST_USE_JWT = True
'''
#https://www.techiediaries.com/django-rest-framework-jwt-tutorial/
JWT_AUTH = {
'JWT_ALLOW_REFRESH': True,
'JWT_RESPONSE_PAYLOAD_HANDLER': 'custom_jwt.jwt_response_payload_handler',
# 'JWT_PAYLOAD_HANDLER': 'custom_jwt.jwt_payload_handler',
# 'JWT_AUTH_HEADER_PREFIX': 'Bearer',
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300)
}
'''
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUTH_HEADER_TYPES': ('Bearer',),
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SITE_ID = 1
Вот модель пользователя
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
class User(AbstractUser):
username = models.CharField(max_length=100,blank=True, null=True)
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'first_name', 'last_name']
def __str__(self):
return "{}".format(self.email)
class UserProfile(models.Model):
USER_TYPE_CHOICES = (
(1, 'ADM'),
(2, 'GEM'),
(3, 'JET'),
(4, 'CAT'),
(5, 'SPR'),
)
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profile')
title = models.CharField(max_length=5)
dob = models.DateField()
address = models.CharField(max_length=255)
country = models.CharField(max_length=50)
city = models.CharField(max_length=50)
zip = models.CharField(max_length=5)
photo = models.ImageField(upload_to='uploads', blank=True)
user_type = models.PositiveSmallIntegerField(choices=USER_TYPE_CHOICES,default=1,unique=False)
Вот вид, к которому я хочу получить доступ
@method_decorator(user_is_ADM,name='dispatch')
class HelloView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request):
content = {'message': 'Hello, World!'}
return Response(content)
Вот пользовательский декоратор, который беспокоит
def user_is_ADM(fun_c):
@wraps(fun_c)
def wrapped(request, *args, **kwargs):
if request.user.profile.user_type == 1: <---throws error here
return fun_c(request, *args, **kwargs)
else:
raise PermissionDenied
return wrapped
Я могу получить пару токенов доступа / обновления из simplejwt, используя http://127.0.0.1:8000/api/token/ с предоставленным именем пользователя и паролем. Но когда я пытаюсь получить доступ к HelloView, используя http://127.0.0.1:8000/core/hello/ (ядро - имя приложения) с accesstoken (конечно, с Authorization: Bearer......), появляется декоратор картина. Теперь этому декоратору требуется request.user, чтобы проверить, является ли пользователь GEM или нет. Проблема в том, что ни один пользователь не вошел в систему, поэтому система выдает мне ошибку, что "Анонимный" пользователь не имеет атрибута "профиль". Даже если я вхожу в систему как предварительное условие, возникает такая же ошибка. Я новичок в django.
Как решить? Есть альтернативные предложения?
1 ответ
С трудом (что хорошо для такого новичка, как я), отладкой, пробами и ошибками я многому научился и решил самостоятельно. Чтобы прийти к решению, мне потребовалась обширная помощь по отладке кода VS, и я рекомендую всем новичкам привыкнуть к этому.
Вот решение. - Я импортировал модель UserProfile, используя
from users.models import UserProfile
затем модифицировал декоратор следующим образом:
def user_is_ADM(fun_c):
@wraps(fun_c)
def wrapped(request, *args, **kwargs):
# 1 = ADM
#u = UserProfile.objects.get()
#if(request.user and request.user.is_authenticated()):
if(request.user and request.user.is_authenticated) :
user_data = UserProfile.objects.get(user_id = request.user.id)
u = user_data.user_type
if u == 1:
return fun_c(request, *args, **kwargs)
else:
raise PermissionDenied
return wrapped
Проверка
- называется / api / token / с действующим именем пользователя и паролем, имеющим. Для пробного использования введите тип пользователя = 'ADM'
- получил токен доступа.
- Затем почтальон используется для вызова helloWorld API с помощью AccessToken (конечно, с авторизацией: Bearer 'токен доступа')
- теперь в игру вступил декоратор, и, как я намеренно предоставил пользователю, он отлично прошел проверку.
- наконец, я смог успешно получить сообщение "привет, мир".
Заключение. Я видел сообщения, в которых пользователи изо всех сил пытались получить аутентификацию с помощью промежуточного программного обеспечения. Кто-нибудь, пожалуйста, подтвердите мой подход. Конечно, @Naveen Jain и @dirkgroten заслуживают похвалы, так как они страстно руководили мной. Верный духу Stackru и братства разработчиков.
Спасибо за ваш интерес...