美文网首页Django
djangorestframework-simplejwt简单使

djangorestframework-simplejwt简单使

作者: Hahn_z | 来源:发表于2020-03-24 10:48 被阅读0次

    我为什么要使用djangorestframework-simplejwt

    现在Django-rest-framework-jwt网上有许多文章
    但是现在Django-rest-framework-jwt停止维护了

    image.png

    djangorestframework-simplejwt详细文档

    安装

    pip install djangorestframework_simplejwt
    

    设置

    在settings.py中

    # drf配置
    REST_FRAMEWORK = {
        # JWT
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework_simplejwt.authentication.JWTAuthentication',
        ),
    
    }
    
    # JWT配置 里面具体配置可以参考文档
    SIMPLE_JWT = {
        'ACCESS_TOKEN_LIFETIME': timedelta(days=7),  # 配置过期时间
        'REFRESH_TOKEN_LIFETIME': timedelta(days=15),
    }
    
    

    在主目录下面的urls.py

    """pine_mountain_bridge URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/3.0/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  path('', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.urls import include, path
        2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
    """
    from django.contrib import admin
    from django.urls import path
    from django.conf.urls import url, include
    from rest_framework.documentation import include_docs_urls
    from rest_framework.routers import DefaultRouter
    from django.views.static import serve
    
    
    
    urlpatterns = [
        path('admin/', admin.site.urls),
    
        # rest_framework_simplejwt自带的得到token
        path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
        # 刷新JWT
        path('api/v1/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
        # 验证token
        path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
    ]
    
    

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

    {
            "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU4NjMxMjYyOSwianRpIjoiZWUzNTQxNmIzMDZjNDIyY2EyOWFiOGQ5NjhlNjc3ZWYiLCJ1c2VyX2lkIjoxfQ.th5AfYNsd9UK3zL9LEhnDRNrd37Ut8ucl-G9VzYlCHI",
            "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNDI5LCJqdGkiOiJlYmI3ZDdmOTBlNzU0OTNkYjM4NTNiNTJkYzA0Yjk3NiIsInVzZXJfaWQiOjF9.WeoTxQ2rG0BOl9ji6KO3yfLm83kcsHV1drFDxGxAvGA",
    }
    

    刷新得到的数据

    {
            "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNTIyLCJqdGkiOiI4MzcyN2UwYWVhMDU0MWYyYmE1ODljOWY5NTMzYjE2OSIsInVzZXJfaWQiOjF9.NTo1YKFl9tvcCYQVmBWLz0rhRL8044qT65jbe7okeG0"
        }
    

    自定义djangorestframework-simplejwt

    在你的serializers.py

    from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
    
    
    class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    
        '''
        token验证
        '''
        def validate(self, attrs):
            data = super().validate(attrs)
    
            refresh = self.get_token(self.user)
    
            data['refresh'] = str(refresh)
            data['access'] = str(refresh.access_token)
            data['username'] = self.user.username #这个是你的自定义返回的
            data['user_id'] = self.user.id #这个是你的自定义返回的
    
            return data
    
    
    

    在你的views.py

    from rest_framework_simplejwt.views import TokenViewBase
    from rest_framework_simplejwt.serializers import TokenRefreshSerializer
    
    from .serializers import *
    from .models import *
    
    
    class MyTokenObtainPairView(TokenObtainPairView):
        """
        自定义得到token username: 账号或者密码 password: 密码或者验证码
        """
        serializer_class = MyTokenObtainPairSerializer
    
    
    class MyTokenRefreshView(TokenViewBase):
        """
        自定义刷新token refresh: 刷新token的元素
        """
        serializer_class = TokenRefreshSerializer
    

    PS 记得写url。我这里就不写了

    得到token

    {
        "msg": "success",
        "code": 1,
        "data": {
            "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU4NjMxMjYyOSwianRpIjoiZWUzNTQxNmIzMDZjNDIyY2EyOWFiOGQ5NjhlNjc3ZWYiLCJ1c2VyX2lkIjoxfQ.th5AfYNsd9UK3zL9LEhnDRNrd37Ut8ucl-G9VzYlCHI",
            "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNDI5LCJqdGkiOiJlYmI3ZDdmOTBlNzU0OTNkYjM4NTNiNTJkYzA0Yjk3NiIsInVzZXJfaWQiOjF9.WeoTxQ2rG0BOl9ji6KO3yfLm83kcsHV1drFDxGxAvGA",
            "username": "hahn",
            "user_id": 1
        }
    }
    

    刷新token

    {
        "msg": "success",
        "code": 1,
        "data": {
            "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNTIyLCJqdGkiOiI4MzcyN2UwYWVhMDU0MWYyYmE1ODljOWY5NTMzYjE2OSIsInVzZXJfaWQiOjF9.NTo1YKFl9tvcCYQVmBWLz0rhRL8044qT65jbe7okeG0"
        }
    }
    

    上面自定义数据结构的传送门

    接口验证

    在你的views.py中

    class UserViewSet(CacheResponseMixin, viewsets.ModelViewSet):
        """
        测试的Api1
        """
        permission_classes = [permissions.IsAuthenticated]  # 权限认证主要是这个
        queryset = User.objects.all()
        serializer_class = UserSerializer
        throttle_classes = []
    
        # 自定义分页
        pagination_class = LisPagination
    

    错误返回

    {
        "msg": "身份认证信息未提供。",
        "state": 0,
        "data": ""
    }
    

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

    截屏2020-03-24上午10.35.52.png 截屏2020-03-24上午10.36.53.png

    现在自定义token接口完成了

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

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

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

    CustomToken.py

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

    返回数据

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

    jwt解码

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

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

    在views.py

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

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

    {
        "msg": "success",
        "status": 200,
        "data": {
            "token_type": "access",
            "exp": 1585710741,
            "jti": "97b42a6570d84108bf09701a60fbf5c1",
            "user_id": 1
        }
    }
    

    djangorestframework-simplejwt退出登录

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

    在setting.py

    # redis配置
    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
                "PASSWORD": "",
            }
        }
    }
    
    # redis缓存时间
    REDIS_TIMEOUT = 60*60*24*7
    

    使用

    from django.core.cache import cache
    

    保存redis缓存

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

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

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

    查看redis缓存

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

    相关文章

      网友评论

        本文标题:djangorestframework-simplejwt简单使

        本文链接:https://www.haomeiwen.com/subject/cponyhtx.html