So, start with a way of managing your tokens. Here's a basic model:
class Token(models.Model):
code = models.CharField(max_length=255)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
expires = models.DateTimeField()
A custom authentication backend can be produced to check the validity of the tokens:
class TokenAuthenticationBackend(ModelBackend):
def authenticate(self, request, token=None):
try:
token = Token.objects.get(code=token, expires__gte=now())
except Token.DoesNotExist:
return None
else:
return token.user
If you're using class-based views, you could write a mixin that checks for the presence of the token then does your authentication logic:
class UrlTokenAuthenticationMixin:
def dispatch(self, request, *args, **kwargs):
if 'token' in request.GET:
user = authenticate(request, request.GET['token'])
if user:
login(request, user)
return super(UrlTokenAuthenticationMixin, self).dispatch(request, *args, **kwargs)
To use this on a given view, just declare your views as follows:
class MyView(UrlTokenAuthenticationMixin, TemplateView):
# view code here
For example.
An alternative way to implement this as a blanket catch-all would be to use middleware rather than a mixin:
class TokenAuthMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if 'token' in request.GET:
user = authenticate(request, request.GET['token'])
if user:
login(request, user)
return self.get_response(request)