É uma boa prática ter clientes móveis renovando periodicamente seu token de autenticação. É claro que isso depende do servidor.
A classe TokenAuthentication padrão não oferece suporte para isso, mas você pode estendê-la para obter essa funcionalidade.
Por exemplo:
from rest_framework.authentication import TokenAuthentication, get_authorization_header
from rest_framework.exceptions import AuthenticationFailed
class ExpiringTokenAuthentication(TokenAuthentication):
def authenticate_credentials(self, key):
try:
token = self.model.objects.get(key=key)
except self.model.DoesNotExist:
raise exceptions.AuthenticationFailed('Invalid token')
if not token.user.is_active:
raise exceptions.AuthenticationFailed('User inactive or deleted')
# This is required for the time comparison
utc_now = datetime.utcnow()
utc_now = utc_now.replace(tzinfo=pytz.utc)
if token.created < utc_now - timedelta(hours=24):
raise exceptions.AuthenticationFailed('Token has expired')
return token.user, token
Também é necessário substituir a visualização de login da estrutura restante padrão, para que o token seja atualizado sempre que um login for feito:
class ObtainExpiringAuthToken(ObtainAuthToken):
def post(self, request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
token, created = Token.objects.get_or_create(user=serializer.validated_data['user'])
if not created:
# update the created time of the token to keep it valid
token.created = datetime.datetime.utcnow()
token.save()
return Response({'token': token.key})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
obtain_expiring_auth_token = ObtainExpiringAuthToken.as_view()
E não se esqueça de modificar os urls:
urlpatterns += patterns(
'',
url(r'^users/login/?$', '<path_to_file>.obtain_expiring_auth_token'),
)
Se alguém estiver interessado por essa solução, mas quiser ter um token que seja válido por um certo tempo, ele será substituído por um novo token aqui está a solução completa (Django 1.6):
yourmodule / views.py:
yourmodule / urls.py:
seu projeto urls.py (na matriz urlpatterns):
yourmodule / authentication.py:
Nas configurações de REST_FRAMEWORK, adicione ExpiringTokenAuthentication como uma classe de autenticação em vez de TokenAuthentication:
fonte
'ObtainExpiringAuthToken' object has no attribute 'serializer_class'
quando tento acessar o endpoint da API. Não tenho certeza do que estou perdendo.Tentei a resposta @odedfos, mas ocorreu um erro enganador . Aqui está a mesma resposta, fixa e com importações adequadas.
views.py
authentication.py
fonte
Pensei em dar uma resposta Django 2.0 usando DRY. Alguém já criou isso para nós, google Django OAuth ToolKit. Disponível com pip
pip install django-oauth-toolkit
,. Instruções sobre como adicionar o token ViewSets com roteadores: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html . É semelhante ao tutorial oficial.Então, basicamente, OAuth1.0 era mais a segurança de ontem, que é o que TokenAuthentication é. Para obter tokens de expiração sofisticados, o OAuth2.0 está na moda atualmente. Você obtém uma variável AccessToken, RefreshToken e uma variável de escopo para ajustar as permissões. Você acaba com creds como este:
fonte
O autor perguntou
Mas todas as respostas estão escrevendo sobre como alterar automaticamente o token.
Acho que mudar token periodicamente por token não tem sentido. O restante do framework cria um token de 40 caracteres, se o invasor testar 1000 tokens a cada segundo, é necessário
16**40/1000/3600/24/365=4.6*10^7
leva anos para obter o token. Você não deve se preocupar se o invasor irá testar seu token um por um. Mesmo que você tenha alterado seu token, a probabilidade de adivinhar seu token é a mesma.Se você está preocupado que talvez os invasores possam obter seu token, então você o altera periodicamente, depois que o invasor obter o token, ele também pode alterar seu token, então o usuário real é expulso.
O que você realmente deve fazer é evitar que o invasor obtenha o token do seu usuário, use https .
A propósito, estou apenas dizendo que alterar token por token não faz sentido, mas alterar token por nome de usuário e senha às vezes é significativo. Talvez o token seja usado em algum ambiente http (você deve sempre evitar esse tipo de situação) ou algum terceiro (neste caso, você deve criar um tipo diferente de token, usar oauth2) e quando o usuário está fazendo algo perigoso como mudar vinculando a caixa de correio ou excluir a conta, você deve ter certeza de não usar mais o token de origem, pois ele pode ter sido revelado pelo invasor usando ferramentas sniffer ou tcpdump.
fonte
Você pode aproveitar http://getblimp.github.io/django-rest-framework-jwt
Esta biblioteca é capaz de gerar tokens com data de validade
Para entender a diferença entre o token padrão DRF e o token fornecido pelo DRF, dê uma olhada em:
Como fazer a autenticação Django REST JWT escalar com vários servidores da web?
fonte
Se você notar que um token é como um cookie de sessão, você pode manter o tempo de vida padrão dos cookies de sessão no Django: https://docs.djangoproject.com/en/1.4/ref/settings/#session-cookie-age .
Não sei se o Django Rest Framework lida com isso automaticamente, mas você sempre pode escrever um script curto que filtra os desatualizados e os marca como expirados.
fonte
Só pensei em adicionar o meu, pois isso foi útil para mim. Eu geralmente uso o método JWT, mas às vezes algo assim é melhor. Atualizei a resposta aceita para django 2.1 com as importações adequadas.
autenticação.py
views.py
fonte
apenas para continuar adicionando à resposta @odedfos, acho que houve algumas mudanças na sintaxe, então o código de ExpiringTokenAuthentication precisa de alguns ajustes:
Além disso, não se esqueça de adicioná-lo a DEFAULT_AUTHENTICATION_CLASSES em vez de rest_framework.authentication.TokenAuthentication
fonte