Django restframework Token擁有不過期的認證
REST框架中的Token認證不像Session認證一樣,它是沒有辦法設置過期時間的,但是有時我們需要對Token做過期驗證,比如說用戶在A設備登陸之后獲取一個Token,如果用戶在沒有清空瀏覽器緩存的情況下,Token將一直保存在緩存中,一周后在訪問依舊有效,但我們並不希望這樣,我們覺得Token認證應該和Session一樣都有過期時間,過期之后作廢。
-
首先,看下
TokenAuthentication模塊的源碼如下:class TokenAuthentication(BaseAuthentication): keyword = 'Token' model = None def get_model(self): if self.model is not None: return self.model from rest_framework.authtoken.models import Token return Token def authenticate(self, request): auth = get_authorization_header(request).split() if not auth or auth[0].lower() != self.keyword.lower().encode(): return None if len(auth) == 1: msg = _('Invalid token header. No credentials provided.') raise exceptions.AuthenticationFailed(msg) elif len(auth) > 2: msg = _('Invalid token header. Token string should not contain spaces.') raise exceptions.AuthenticationFailed(msg) try: token = auth[1].decode() except UnicodeError: msg = _('Invalid token header. Token string should not contain invalid characters.') raise exceptions.AuthenticationFailed(msg) return self.authenticate_credentials(token) def authenticate_credentials(self, key): # key=前端在請求頭傳過來的Token model = self.get_model() # 獲取Token模塊 try: token = model.objects.select_related('user').get(key=key) # 通過key獲取Token except model.DoesNotExist: raise exceptions.AuthenticationFailed(_('Invalid token.')) # 如果沒有就報錯 if not token.user.is_active: raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) # 如果用戶沒有激活也報錯 return (token.user, token) def authenticate_header(self, request): return self.keyword # 然后把Token和登錄的用戶返回給View
上面有注解的地方是關鍵。 過期驗證,就相當於多加一個判斷,只要繼承該類,然后重寫authenticate_credentials方法即可。以下是我實現的例子,以expiringTokenAuthentication.py保存。
from rest_framework.authentication import TokenAuthentication from django.utils.translation import ugettext_lazy as _ from rest_framework import exceptions from django.utils import timezone from datetime import timedelta from django.conf import settings class ExpiringTokenAuthentication(TokenAuthentication): def authenticate_credentials(self, key): model = self.get_model() try: token = model.objects.select_related('user').get(key=key) except model.DoesNotExist: raise exceptions.AuthenticationFailed(_('Invalid token.')) if not token.user.is_active: raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) if timezone.now() > (token.created + timedelta(DAYS)): # 重點就在這句了,這里做了一個Token過期的驗證,如果當前的時間大於Token創建時間+DAYS天,那么久返回Token已經過期 raise exceptions.AuthenticationFailed(_('Token has expired')) return (token.user, token)
以此類推, 要對token進行類似的判斷,都可以按上面的代碼進行仿寫。
