-
-
Save AndrewPix/cdd9276b1d5683459b965d5cc4517b26 to your computer and use it in GitHub Desktop.
from rest_framework import serializers | |
from rest_auth.serializers import UserDetailsSerializer | |
class KnoxSerializer(serializers.Serializer): | |
""" | |
Serializer for Knox authentication. | |
""" | |
token = serializers.CharField() | |
user = UserDetailsSerializer() |
AUTHENTICATION_BACKENDS = ( | |
'django.contrib.auth.backends.ModelBackend', | |
'allauth.account.auth_backends.AuthenticationBackend', | |
) | |
REST_FRAMEWORK = { | |
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication',), | |
'DEFAULT_PERMISSION_CLASSES': ( | |
'rest_framework.permissions.IsAuthenticated', | |
), | |
'DEFAULT_FILTER_BACKENDS': ( | |
'django_filters.rest_framework.DjangoFilterBackend', | |
), | |
} | |
REST_AUTH_TOKEN_MODEL = 'knox.models.AuthToken' | |
REST_AUTH_TOKEN_CREATOR = 'project.apps.accounts.utils.create_knox_token' | |
REST_AUTH_SERIALIZERS = { | |
'USER_DETAILS_SERIALIZER': 'project.apps.accounts.serializers.UserDetailsSerializer', | |
'TOKEN_SERIALIZER': 'project.apps.accounts.serializers.KnoxSerializer', | |
} |
from knox.models import AuthToken | |
def create_knox_token(token_model, user, serializer): | |
token = AuthToken.objects.create(user=user) | |
return token |
from rest_framework.response import Response | |
from rest_auth.views import LoginView | |
from rest_auth.registration.views import RegisterView | |
from allauth.account.utils import complete_signup | |
from allauth.account import app_settings as allauth_settings | |
from .serializers import KnoxSerializer | |
from .utils import create_knox_token | |
class KnoxLoginView(LoginView): | |
def get_response(self): | |
serializer_class = self.get_response_serializer() | |
data = { | |
'user': self.user, | |
'token': self.token | |
} | |
serializer = serializer_class(instance=data, context={'request': self.request}) | |
return Response(serializer.data, status=200) | |
class KnoxRegisterView(RegisterView): | |
def get_response_data(self, user): | |
return KnoxSerializer({'user': user, 'token': self.token}).data | |
def perform_create(self, serializer): | |
user = serializer.save(self.request) | |
self.token = create_knox_token(None, user, None) | |
complete_signup(self.request._request, user, allauth_settings.EMAIL_VERIFICATION, None) | |
return user |
Love this and it's working fine except for one thing. After logging in, the expiry date is not included in the response.
urls.py
path('api/v1/', include("api.urls")),
path('api/v1/login/', KnoxLoginView.as_view(), name='knox_login'),
path('api-auth/', include('rest_framework.urls')),
path('api/v1/dj-rest-auth/', include('dj_rest_auth.urls')),
views.py
from dj_rest_auth.views import LoginView
class KnoxLoginView(LoginView):
def get_response(self):
serializer_class = self.get_response_serializer()
print(self)
data = {
'user': self.user,
'token': self.token
}
serializer = serializer_class(instance=data, context={'request': self.request})
return Response(serializer.data, status=200)
settings.py
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
),
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication',),
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
REST_AUTH_TOKEN_MODEL = 'knox.models.AuthToken'
REST_AUTH_TOKEN_CREATOR = 'api.utils.create_knox_token'
REST_AUTH_SERIALIZERS = {
'USER_DETAILS_SERIALIZER': 'api.serializers.UserDetailsSerializer',
'TOKEN_SERIALIZER': 'api.serializers.KnoxSerializer',
}
from rest_framework.settings import api_settings
REST_KNOX = {
'TOKEN_TTL': timedelta(minutes=1),
'TOKEN_LIMIT_PER_USER': None,
'AUTO_REFRESH': False,
'EXPIRY_DATETIME_FORMAT': api_settings.DATETIME_FORMAT
}
api.utils
from knox.models import AuthToken
def create_knox_token(token_model, user, serializer):
token = AuthToken.objects.create(user=user)
return token
This is brilliant! Thanks.
One question,
I'm using dj-rest-auth, an extension of django-rest-auth, and I've tried to integrate django-rest-knox with it in your code.
I then POST the API to try and register with the URL http://127.0.0.1:8000/dj-rest-auth/registration/ and the result was that the token was stored in the AuthToken model and at the same time the User model (which is not the Django standard but, CustomUserModel. ) has also saved the user's record .
However, an
"AttributeError at /dj-rest-auth/registration/ 'CustomUser' object has no attribute 'auth_token'"
error.
I thought it was because the User model does not have an auth_token field, so I tried to migrate it again.
But as a result I get the error
"users.CustomUser.auth_token: (models.E006) The field 'auth_token' clashes with the field 'auth_token' "
from model 'users.customuser'.I can't figure out why I'm getting an
"AttributeError at /dj-rest-auth/registration/ 'CustomUser' object has no attribute 'auth_token'"
errorr .
Could you please advise me on how to resolve this? I can attach the code such as models.py separately if needed.
I'm Japanese, I'm not very good at English and I don't have much programming experience. Feel free to tell me if there is something difficult to understand in your question.
Main reason behind this is that,
When you are using dj_rest_auth registration method
In RegisterView there is method called get_response_data(self, user) which
return TokenSerializer(user.auth_token, context=self.get_serializer_context()).data
Here user.auth_token is main cause of errors raises
when you look on AuthToken in knox.models ,you found
user = models.ForeignKey(User, null=False, blank=False,
related_name='auth_token_set', on_delete=models.CASCADE)
whose related_name is auth_token_set not auth_token
Solution for this is,
1.Try to use custom register view as mention above
or change the auth_token to auth_token_set by overriding the
get_response_data(self, user) method of dj_rest_auth.registration.views.registerview
Hope you got it..
make sure that you have the correct urlpattern order and that you have added the KnoxLoginView in the urlpattern. I changed the urlpattern to the following:
Hope this helps!
P.S.: make sure that you change your code to what it was when you got the attribute error..