Great, I figured out in hours that knox doesn't come with full token_key stored in database.
Real token we can get is something like:
a512529e7ffceaa8406ceb616d088b3422ad15811a5eb470e8f4c4896c9aa649
In database token_key is stored by default a512529e
. 8 digits.
Filter objects using this:
knox_object = AuthToken.objects.filter(token_key__startswith=token[:8]).first()
Then get user object
knox_object.user.username
Or you can use this, faster
from knox.settings import CONSTANTS
knox_object = AuthToken.objects.filter(token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH]).first()
From the knox source codes
class CONSTANTS:
'''
Constants cannot be changed at runtime
'''
TOKEN_KEY_LENGTH = 8
DIGEST_LENGTH = 128
SALT_LENGTH = 16
def __setattr__(self, *args, **kwargs):
raise Exception('''
Constant values must NEVER be changed at runtime, as they are
integral to the structure of database tables
''')
CONSTANTS = CONSTANTS()
You can see TOKEN_KEY_LENGTH
is of 8 digits.
I wrote a simple function to do that
from knox.models import AuthToken
from knox.settings import CONSTANTS
def get_user_from_token(token):
objs = AuthToken.objects.filter(token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH])
if len(objs) == 0:
return None
return objs.first().user
Life be easier now. :)
Yes, I improved it and published it.
You may try my fork. If you just simply want to add @smart_token_user
before any GET/POST/PUT/... methods.
https://github.com/xros/django-rest-knox
Just git clone, and pip install ./
I wrote a decorator.
With this,
in our app views.py
we can easily get user object by doing so,@smart_token_user
will modify the request handler. We can have a request.user
attr only once the token is valid. And all invalid attempts will be thrown out with HTTP 401 Unauthorized response.
Life can be easier with this decorator.
from knox.models import smart_token_user
class CheckUserEmail(generics.RetrieveAPIView):
permission_classes = (IsAuthenticated,)
@smart_token_user
def get(self, request):
return Response({
"username": request.user.username,
"email": request.user.email,
"password": request.user.password,
}, status=status.HTTP_200_OK)
Or use this like original if you want: authentication_classes = (TokenAuthentication,)
class CheckUserEmail(generics.RetrieveAPIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
def get(self, request):
return Response({
"username": request.user.username,
"email": request.user.email,
"password": request.user.password,
}, status=status.HTTP_200_OK)