当前位置: 首页 > 图灵资讯 > 技术篇> 优化Django Rest Framework 的Token验证功能

优化Django Rest Framework 的Token验证功能

来源:图灵教育
时间:2023-06-04 09:09:39

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,减少数据库查询。