m4rtin
m4rtin

Reputation: 31

Get user object from token string in DRF Token In Django using Knox Token

I have question related with Django . I am using Knox Token Authentication to generate tokens for every user when he log in on the page.

Now I want to use that token for every request that will send so I can get the corresponding user for the token. Also I am using custom function example def dashboard(request) in Django for every URL route.

I have see on youtube that there are option to get user from token but is not with functions

    class UserAPI(generics.RetrieveAPIView):
        permission_classes = [
         permissions.IsAuthenticated,
        ]
        serializer_class = UserSerializer

        def get_object(self):
          return self.request.user

So is there a whey to get the corresponding user from a token within a custom function

Upvotes: 2

Views: 2288

Answers (2)

I think the below is a better and more secure way to implement it

from knox.auth import TokenAuthentication

auth = TokenAuthentication()
user = auth.authenticate_credentials(token)[0]

Upvotes: 0

dotslash
dotslash

Reputation: 381

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)

Upvotes: 0

Related Questions