14

I'd like to use Django Rest Framework auth but I want to have more than one token for one user. In order to do that I need to implement my own Token model, I found this in Token authentication class:

class TokenAuthentication(BaseAuthentication):
    """
    Simple token based authentication.
    ...
    """

    model = Token
    """
    A custom token model may be used, but must have the following properties.

    * key -- The string identifying the token
    * user -- The user to which the token belongs
    """

But I don't have an idea how I can specify this model. Should I subclass TokenAuthentication?

Dmitrii Mikhailov
  • 5,053
  • 7
  • 43
  • 69

2 Answers2

17

Define you own authentication method in settings.py:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'my_project.my_app.authentication.MyOwnTokenAuthentication',
     ),
}

In authentication.py:

from rest_framework.authentication import TokenAuthentication
from my_project.my_app.models.token import MyOwnToken

class MyOwnTokenAuthentication(TokenAuthentication):
    model = MyOwnToken

In models.py:

import binascii
import os

from django.db import models
from django.utils.translation import ugettext_lazy as _
from my_project.companies.models import Company


class MyOwnToken(models.Model):
    """
    The default authorization token model.
    """
    key = models.CharField(_("Key"), max_length=40, primary_key=True)

    company = models.OneToOneField(
        Company, related_name='auth_token',
        on_delete=models.CASCADE, verbose_name="Company"
    )
    created = models.DateTimeField(_("Created"), auto_now_add=True)

    class Meta:
        verbose_name = _("Token")
        verbose_name_plural = _("Tokens")

    def save(self, *args, **kwargs):
        if not self.key:
            self.key = self.generate_key()
        return super(MyOwnToken, self).save(*args, **kwargs)

    def generate_key(self):
        return binascii.hexlify(os.urandom(20)).decode()

    def __str__(self):
        return self.key
radtek
  • 34,210
  • 11
  • 144
  • 111
mullerivan
  • 1,833
  • 1
  • 14
  • 15
  • but, how can I call "MyOwnTokenAuthentication" from view? – Raju Singh Dec 09 '20 at 10:49
  • 2
    @RajuSingh you don't need to add anything to views, after you define DEFAULT_AUTHENTICATION_CLASSES, you're defining MyOwnTokenAuthentication as middleware function. Then, on your APIViews, you can access the authenticated user with "self.request.user" . You can also define authentication per view basis: authentication_classes = [MyOwnTokenAuthentication] – Souza Feb 05 '21 at 19:45
  • Getting `'MyOwnToken' object has no attribute 'user'` when trying to use this approach. It seems to me that it still has to be connected with a user, is that correct? – Michal Šrůtek Mar 13 '22 at 06:42
9

What that message is saying is that the model Token can be swapped out with any other model, as long as it has properties key and user. That way, if, for instance, you want a more complicated way to generate token keys, you can define your own model.

So if you want a custom Token model, you should do the following:

  1. Subclass the Token model from rest_framework.authtoken.models. Add whatever custom behavior you want here, but make sure it has a key property and user property.
  2. Subclass the TokenAuthentication class from rest_framework.authentication. Set its model property to whatever your new Token model is.
  3. Make sure to reference your new authentication class in whatever views you want.
Jamie
  • 2,181
  • 1
  • 21
  • 35
  • 1
    Hi Jamie, i'm using rest_framework.authtoken.models Token. i can see 3 fields which is key, created_at and user_id. my question is how can i add an extra field like company_id to that model? Thanks – Binsoi Jun 07 '16 at 02:23