token + ssl,在线脚本的调用简化方便。Django版本1.8.16.djangorestframework版本3.5.3.使用框架提供的rest_framework.authtoken.views.obtain_auth_token和rest_framework.authentication.TokenAuthentication后,发现前者认证通过创建token后,token不会自动更新,非常不安全和危险。后者验证时没有缓存,需要查询数据库。因为每个请求都需要验证token,所以请求相当频繁,感觉不是很酷。
1、实现生成的token带过期时间首先在setting.py配置文件设置过期时间 REST_FRAMEWORK_TOKEN_EXPIRE_MINUTES,60分钟设置在这里
# REST_FRAMEWORK_TOKEN_EXPIRE_MINUTES = 60 #
setting.viewwwpy同一目录文件.py编辑视图
# #coding=utf8 import datetime from django.conf import settings from rest_framework import status from rest_framework.response import Response from rest_framework.authtoken.models import Token from rest_framework.authtoken.views import ObtainAuthToken EXPIRE_MINUTES = getattr (settings, 'REST_FRAMEWORK_TOKEN_EXPIRE_MINUTES' , 1 ) class ObtainExpiringAuthToken(ObtainAuthToken): """Create user token""" 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' ]) time_now = datetime.datetime.now() if created or token.created < time_now - datetime.timedelta(minutes = EXPIRE_MINUTES): # Update the created time of the token to keep it valid token.delete() token = Token.objects.create(user = serializer.validated_data[ 'user' ]) token.created = time_now token.save() return Response({ 'token' : token.key}) return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST) obtain_expiring_auth_token = ObtainExpiringAuthToken.as_view() #
url.用于生成用户token的py新url
# #from rest_framework.authtoken.views import obtain_auth_token from .views import obtain_expiring_auth_token urlpatterns + = [ #url(r'^api/token/', obtain_auth_token, name='api-token'), url(r '^api/token/' , obtain_expiring_auth_token, name = 'api-token' ), ] #
用curl测试接口 api/token/
# git:(master) ✗ curl -H "Content-Type: application/json" -X POST -d '{"username":"test","password":"test"}' http: //127 .0.0.1:9000 /api/token/ { "token" : “6ff54785241f82544cfca61ceb6be7f91e” }% #
然后,生成token的接口就好了。目前还有一个问题,用户就是生成token,比如A,然后用户再也不会要求这个接口生成token,那么这个用户的token呢? A将永远生效,不会更新,因此需要结合token验证函数,强制删除用户过期的token。
2、自定义token验证,强制删除过期token,顺便说一句,没有过期的token首先在setting中缓存.py文件新增全球认证api.authentication.Expiringtokenauthentication替换默认rest_framework.authentication.TokenAuthentication
# REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES' : [ 'rest_framework.authentication.BasicAuthentication' , #'rest_framework.authentication.TokenAuthentication', #enable Token authentication 'api.authentication.ExpiringTokenAuthentication' ], 'PAGE_SIZE' : 10 , } #
新建authentication.py文件,在api目录下更改文件。
# #coding=utf8 import datetime from django.conf import settings from rest_framework.authentication import TokenAuthentication from rest_framework import exceptions from django.utils.translation import ugettext_lazy as _ from django.core.cache import cache EXPIRE_MINUTES = getattr (settings, 'REST_FRAMEWORK_TOKEN_EXPIRE_MINUTES' , 1 ) class ExpiringTokenAuthentication(TokenAuthentication): """Set up token expired time""" def authenticate_credentials( self , key): # Search token in cache cache_user = cache.get(key) if cache_user: return (cache_user, 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.' )) time_now = datetime.datetime.now() if token.created < time_now - datetime.timedelta(minutes = EXPIRE_MINUTES): token.delete() raise exceptions.AuthenticationFailed(_( 'Token has expired then delete.' )) if token: # Cache token cache. set (key, token.user, EXPIRE_MINUTES * 60 ) return (token.user, token) #
然后,实现所有功能,删除用户过期的token和缓存token,减少数据库查询。