django-restframework-simplejwt使用

安装

  1. pip install djangorestframework_simplejwt

设置

在settings.py中 ```python

drf配置

REST_FRAMEWORK = {

  1. # JWT
  2. 'DEFAULT_AUTHENTICATION_CLASSES': (
  3. 'rest_framework_simplejwt.authentication.JWTAuthentication',
  4. ),

}

JWT配置 里面具体配置可以参考文档

SIMPLE_JWT = { ‘ACCESS_TOKEN_LIFETIME’: timedelta(days=7), # 配置过期时间 ‘REFRESH_TOKEN_LIFETIME’: timedelta(days=15), }

  1. > 在主目录下面的urls.py
  2. > ```python
  3. """djangoProject15 URL Configuration
  4. The `urlpatterns` list routes URLs to views. For more information please see:
  5. https://docs.djangoproject.com/en/3.1/topics/http/urls/
  6. Examples:
  7. Function views
  8. 1. Add an import: from my_app import views
  9. 2. Add a URL to urlpatterns: path('', views.home, name='home')
  10. Class-based views
  11. 1. Add an import: from other_app.views import Home
  12. 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
  13. Including another URLconf
  14. 1. Import the include() function: from django.urls import include, path
  15. 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
  16. """
  17. from django.contrib import admin
  18. from django.urls import path, include
  19. from rest_framework_simplejwt.views import (TokenObtainPairView, TokenRefreshView)
  20. urlpatterns = [
  21. path('admin/', admin.site.urls),
  22. path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
  23. path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
  24. ]

得到token数据返回
refresh书用来刷新的
access是token

  1. {
  2. "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMTQ4ODk4MywianRpIjoiZWYyMDE1YzMwYzkwNGZlZjg0ZDNmM2ZiMmFiMDBmZDgiLCJ1c2VyX2lkIjozfQ.6fy8Dz6KDiBdTKBVAhjwi1jputZixD3yEJsFOY9JRFE",
  3. "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyMDA3MzgzLCJqdGkiOiI1ZDVhZTM5MTY2ZTk0NDYwYmFhYTRlODE5NTAyYmY1ZiIsInVzZXJfaWQiOjN9.seodK-XcsbgZ5AgwONxGzlDAFY3v5THQyiU-h7c-DE8"
  4. }

刷新得到的数据

  1. {
  2. "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNTIyLCJqdGkiOiI4MzcyN2UwYWVhMDU0MWYyYmE1ODljOWY5NTMzYjE2OSIsInVzZXJfaWQiOjF9.NTo1YKFl9tvcCYQVmBWLz0rhRL8044qT65jbe7okeG0"
  3. }

自定义djangorestframework-simplejwt

在你的serializers.py ```python from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):

  1. '''
  2. token验证
  3. '''
  4. def validate(self, attrs):
  5. data = super().validate(attrs)
  6. refresh = self.get_token(self.user)
  7. data['refresh'] = str(refresh)
  8. data['access'] = str(refresh.access_token)
  9. data['username'] = self.user.username #这个是你的自定义返回的
  10. data['user_id'] = self.user.id #这个是你的自定义返回的
  11. return data
  1. > 在你的views.py
  2. > ```python
  3. from rest_framework_simplejwt.views import TokenViewBase
  4. from rest_framework_simplejwt.serializers import TokenRefreshSerializer
  5. from .serializers import *
  6. from .models import *
  7. class MyTokenObtainPairView(TokenObtainPairView):
  8. """
  9. 自定义得到token username: 账号或者密码 password: 密码或者验证码
  10. """
  11. serializer_class = MyTokenObtainPairSerializer
  12. class MyTokenRefreshView(TokenViewBase):
  13. """
  14. 自定义刷新token refresh: 刷新token的元素
  15. """
  16. serializer_class = TokenRefreshSerializer

在你的url.py中ur

  1. urlpatterns = [
  2. """
  3. 其他路由
  4. """
  5. path('token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
  6. path('token/refresh/', MyTokenRefreshView.as_view(), name='token_refresh'),
  7. ]

得到token ```json

{ “refresh”: “eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMTQ4OTQ0MiwianRpIjoiNGE4NjkwZDQ0MTVlNDBlNzkxMThhOGYzZTUyODdlYzAiLCJ1c2VyX2lkIjozfQ.DaCk2ADDDgof4l8goL4PZkDAVpGHcplYCry8mFI452M”, “access”: “eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyMDA3ODQyLCJqdGkiOiJkZjY2MGE3MWRmZmU0MGFlYjRkMzRmOTNjYzk0NThkNSIsInVzZXJfaWQiOjN9.boLQPtnnW10EVN2lUon6AG0N537E6Y5eadx5ttqnysg”, “username”: “admins”, “user_id”: 3 }

  1. > 刷新token
  2. > ```json
  3. {
  4. "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMTQ4OTY2NiwianRpIjoiODgxNGE3M2YyNGY1NGM0ZGIyZjVlNGFiMGRiNmI2ZTIiLCJ1c2VyX2lkIjozfQ.LhlzCuxLdzwWq14V1Bu7pd19VZnIGCZHd1Cl3_6hNiI",
  5. "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyMDA4MDY2LCJqdGkiOiJlMzY2ZWJkOWVhYTA0NGI0YjZjMTk2N2RjM2U1MGRlOCIsInVzZXJfaWQiOjN9.VM2iMCB7GSi563np-kFdsgZ5337cLiHHE4p96n8G7dA",
  6. "username": "admins",
  7. "user_id": 3
  8. }

接口验证

在你的views.py中 ```python class UserViewSet(CacheResponseMixin, viewsets.ModelViewSet): “”” 测试的Api1 “”” permission_classes = [permissions.IsAuthenticated] # 权限认证主要是这个 queryset = User.objects.all() serializer_class = UserSerializer throttle_classes = []

  1. # 自定义分页
  2. pagination_class = LisPagination
  1. > 错误返回
  2. > ```json
  3. {
  4. "msg": "身份认证信息未提供。",
  5. "state": 0,
  6. "data": ""
  7. }

这个token是加在请求头的Authorization
太长就截图看了

太长就截图看了

django-restframework-simplejwt使用 - 图1 django-restframework-simplejwt使用 - 图2

现在自定义token接口完成了

但是drf jwt默认验证的是username和password
突然想验证手机号码或者其他什么的只是自定义了
PS:本来想换请求数据中的key的、就是不要username、password。因为能力有限暂时不知道怎么换。看了好久源码好像是和Django user模型绑定了

在settings.py中
pine_mountain_bridge里面的utils新建CustomToken.py

  1. # 自定义JWT校验
  2. AUTHENTICATION_BACKENDS = (
  3. 'pine_mountain_bridge.utils.CustomToken.CustomBackend',
  4. )

CustomToken.py

  1. # 自定义得到token校验
  2. from django.contrib.auth.backends import ModelBackend
  3. from django.db.models import Q
  4. from rest_framework import serializers
  5. from users.models import *
  6. class CustomBackend(ModelBackend):
  7. def authenticate(self, request, username=None, password=None, **kwargs):
  8. # print(request.data) 参考请求的其他数据
  9. # print(request.data['demo']) 比如说key是demo的数据用来做你要的数据校验
  10. try:
  11. # 小编这里添加了一个手机验证,如果需要其他验证再加就ok了
  12. try:
  13. user = Users.objects.get(Q(username=username) | Q(mobile=username))
  14. except Exception:
  15. raise serializers.ValidationError({'': '账号没有注册'})
  16. if user.check_password(password):
  17. return user
  18. else:
  19. # 如果不想密码登录也可以验证码在这里写
  20. # 这里做验证码的操作
  21. raise serializers.ValidationError({'': '密码错误'})
  22. except Exception as e:
  23. raise e

返回数据

django-restframework-simplejwt使用 - 图3

截屏2020-03-24上午10.45.40.png

jwt解码

根据token返回对于的数据
在你的serializers.py

  1. from rest_framework_simplejwt.serializers import TokenVerifySerializer
  2. from jwt import decode as jwt_decode
  3. class MyTokenVerifySerializer(TokenVerifySerializer):
  4. """
  5. token验证
  6. """
  7. def validate(self, attrs):
  8. """
  9. attrs['token']: 是请求的token
  10. settings.SECRET_KEY: setting.py默认的key 除非在配置文件中修改了
  11. algorithms: 加密的方法
  12. """
  13. decoded_data = jwt_decode(attrs['token'], settings.SECRET_KEY, algorithms=["HS256"])
  14. return decoded_data

在views.py

  1. from rest_framework_simplejwt.views import TokenObtainPairView, TokenViewBase
  2. class MyTokenVerifyView(TokenViewBase):
  3. """
  4. 验证token得到用户信息 token: 验证的token
  5. """
  6. serializer_class = MyTokenVerifySerializer

返回的数据
user_id就是你的用户ID

  1. {
  2. "msg": "success",
  3. "status": 200,
  4. "data": {
  5. "token_type": "access",
  6. "exp": 1585710741,
  7. "jti": "97b42a6570d84108bf09701a60fbf5c1",
  8. "user_id": 1
  9. }
  10. }

djangorestframework-simplejwt退出登录

JWT是不带退出内置的办法的
JWT退出登录很多方法
我这里是使用Django-redis库、用redis管理JWT的状态。用用户作为key保存token。
因为每个人的业务逻辑不一样、我就贴一些关键的代码

在setting.py

  1. # redis配置
  2. CACHES = {
  3. "default": {
  4. "BACKEND": "django_redis.cache.RedisCache",
  5. "LOCATION": "redis://127.0.0.1:6379",
  6. "OPTIONS": {
  7. "CLIENT_CLASS": "django_redis.client.DefaultClient",
  8. "PASSWORD": "",
  9. }
  10. }
  11. }
  12. # redis缓存时间
  13. REDIS_TIMEOUT = 60*60*24*7

使用

  1. from django.core.cache import cache

保存redis缓存

  1. # 设置redis缓存
  2. # redis_key你的key
  3. # token token
  4. # REDIS_TIMEOUT 保存的数据
  5. cache.set(redis_key, token, REDIS_TIMEOUT)

清除redis缓存
我这里是把value变成空了、方便我判断

  1. # 设置redis缓存
  2. # redis_key你的key
  3. # REDIS_TIMEOUT 保存的数据
  4. cache.set(redis_key,'', REDIS_TIMEOUT)

查看redis缓存

  1. # 解码token得到user_id
  2. decoded_data = jwt_decode(token algorithms=["HS256"])
  3. # redis_key 你设置的redis的key
  4. results = cache.get(redis_key)
  5. # 判断、写自己的业务逻辑