【DRF配置管理】如何实现JWT身份验证

原文作者:我辈李想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。

DRF应用和管理

【DRF配置管理】Django安装DRF框架并生成openapi风格文档
【DRF配置管理】如何实现JWT身份验证
【DRF配置管理】如何使用序列化:验证码、注册和登录
【DRF配置管理】如何结合ORM实现排序、模糊搜索、范围查询
【DRF配置管理】如何在视图类使用get_objects()
【DRF配置管理】如何实现RBAC页面菜单和按钮权限
【DRF配置管理】如何建立coreapi风格api接口文档
【DRF配置管理】如何建立swagger风格api接口文档



前言

django使用jwt验证,可以使用的三方库有好几个,结合drf使用的话,建议使用djangorestframework-simplejwt第三方库,能够很好的完成jwt验证。官方推荐djangorestframework-simplejwt。


一、常见用法

1.安装

pip install djangorestframework-simplejwt

2.配置

# settings.py
INSTALLED_APPS = [
    ...
    'rest_framework_simplejwt',
    ...
]
REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        ...
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
    ...
}
SIMPLE_JWT = {
    # token有效时长(返回的 access 有效时长)
    'ACCESS_TOKEN_LIFETIME': datetime.timedelta(seconds=30),
    # token刷新的有效时间(返回的 refresh 有效时长)
    'REFRESH_TOKEN_LIFETIME': datetime.timedelta(seconds=20),
}

3.路由

# urls.py
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
    TokenVerifyView
)
urlpatterns = [
    # 登录
    path('login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('verify/', TokenVerifyView.as_view(), name='token_verify'),
]

二、request.user的使用

1.request.user包含用户数据

# 配置
REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        ...
        'rest_framework_simplejwt.authentication.JWTAuthentication', # 查询数据库
    )

views.py中代码

class UserInfoView(ModelViewSet):
    """更新用户信息"""
    queryset = UserProfile.objects.all()
    serializer_class = WxUserSerializer

    def retrieve(self, request, *args, **kwargs):
        print(type(self.request.user))  # UserProfile
        print(self.request.user.get_username())  # 有值
        print(self.request.user.get_username())
        print(self.request.user.user_permissions)
        print(self.request.user.groups)
        print(self.request.user.is_authenticated)
        print(type(self.request.user))
        serializer = self.get_serializer(self.request.user)
        print(serializer.data)
        return Response(status=status.HTTP_200_OK,
                        data={'code': 0,
                              'msg': 'ok',
                              'data': serializer.data})

在这里插入图片描述

2.request.user不包含用户数据

# 配置
REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        ...
        'rest_framework_simplejwt.authentication.JWTTokenUserAuthentication', # 不查询数据库
    )

在这里插入图片描述

TokenUser 的位置from rest_framework_simplejwt.models import TokenUser

三、验证、注册和登陆

1.路由配置urls.py

# urls.py
from django.conf.urls import url
from django.urls import include, path

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
    TokenVerifyView
)
from views import *

urlpatterns = [
    # simple jwt 认证接口
    path('login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('verify/', TokenVerifyView.as_view(), name='token_verify'),
    
    path('wx_login/', WxLoginView.as_view()),
    path('user_info/', views.UserInfoView.as_view({'post': 'create', "get": "retrieve"}))
]

2.序列化和反序列化(serializer验证)

# serializer.py
from django.contrib.auth import get_user_model

User = get_user_model()

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['name'] = user.username
        return token

    def validate(self, attrs):
        """
        登录返回token和refresh
        :param attrs:
        :return:
        """
        data = super().validate(attrs)
        data['token'] = str(data["access"])
        return data

class WxUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserProfile
        fields = ['id', 'nick_name', 'avatar_url', 'gender', "phone"]

3.views.py

# views.py
from django.conf import settings


def code2session_key(code):
    API = 'https://api.weixin.qq.com/sns/jscode2session'
    params = 'appid=%s&secret=%s&js_code=%s&grant_type=authorization_code' % (
        settings.WX_APP_ID, settings.WX_APP_SECRET, code)
    url = API + '?' + params
    response = requests.get(url=url)
    data = json.loads(response.text)  # response.json()
    return data

class WxLoginView(APIView):
    """
    登录和注册
    """
    # 认证:跳过JWT token认证
    authentication_classes = []
    permission_classes = []

    @csrf_exempt
    def post(self, request):
        code = json.loads(request.body.decode('utf-8')).get('code')
        if code:
            wx_data = code2session_key(code)
            print("wx_data", wx_data)
            openid = wx_data.get('openid')
            # session_key保存到session中,留作后期调用
            if openid:
                user, flat = UserProfile.objects.get_or_create(openid=openid,
                                                               defaults={'unionid': wx_data.get('unionid'),
                                                                         'session_key': wx_data.get('session_key')})
                # 生成token(JWT)
                if user:
                    # payload = {'openid': openid, "id": user.id, 'unionid': unionid}
                    # token = create_token(payload, timeout=1000 * 24)
                    token = MyTokenObtainPairSerializer.get_token(user).access_token
                    print("token", token)
                    return Response(status=status.HTTP_200_OK,
                                    data={"code": 0,
                                          "msg": "ok",
                                          "user": user.id,
                                          'token': str(token)})
        return Response(status=status.HTTP_200_OK,
                        data={"code": -1,
                              "msg": "无法登录",
                              "user": None,
                              'token': ''})

class UserInfoView(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   GenericViewSet):
    """更新用户信息"""
    queryset = UserProfile.objects.all()
    serializer_class = WxUserSerializer

    def retrieve(self, request, *args, **kwargs):
        print(self.request.user.get_username())
        print(self.request.user.user_permissions)
        print(self.request.user.groups)
        print(self.request.user.is_authenticated)
        print(type(self.request.user))
        serializer = self.get_serializer(self.request.user)
        return Response(status=status.HTTP_200_OK,
                        data={'code': 0,
                              'msg': 'ok',
                              'data': serializer.data})

    def create(self, request):
        try:
            seralizer = WXLoginSerializer(data=request.data, instance=request.user)
            if seralizer.is_valid():
                seralizer.save()
                current_clan = UserClan.objects.filter(user=request.user, is_check=True).first()
                uc_seralizer = UserClanSerializer(current_clan)
                print(seralizer.data)
                return Response(status=status.HTTP_200_OK,
                                data={"code": 0,
                                      "msg": 'ok',
                                      "data": seralizer.data,
                                      'current_clan': uc_seralizer.data})
            else:
                return Response(status=status.HTTP_200_OK,
                                data={"code": -10,
                                      "msg": seralizer.errors,
                                      "data": [],
                                      "current_clan": []})
        except Exception as e:
            print(e)
            return Response(status=status.HTTP_200_OK,
                            data={
                                'code': -10,
                                'msg': '错误' + str(e),
                                'data': []})

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我辈李想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值