设为首页 收藏本站
查看: 949|回复: 0

Django之drf中jwt返回格式、自定制jwt认证、多方式登录、Dj缓存

[复制链接]
累计签到:500 天
连续签到:2 天
发表于 2023-1-2 11:50:58 | 显示全部楼层 |阅读模式
# 作业:
   1 自定义User表,新增mobile唯一约束字段;新增icon图片字段
   2 在自定义User表基础上,用 GenericViewSet + CreateModelMixin + serializer 完成User表新增接口(就是注册接口)(重要提示:序列化类要重写create方法,不然密码就是明文了)
   3 在自定义User表基础上,用 GenericViewSet + RetrieveModelMixin + serializer 完成User表单查(就是用户中心)
   4 在自定义User表基础上,用 GenericViewSet + UpdateModelMixin + serializer 完成用户头像的修改
[urls路由层]
from django.contrib import admin
from django.urls import path,re_path,include
from api import views
from rest_framework.routers import SimpleRouter
router=SimpleRouter()
router.register('register',views.RegisterView,'register')
urlpatterns =
[
    # path('register/', views.RegisterView.as_view({'post':'create'})),
    path('',include(router.urls)),# 第二种自动生成路由
]
urlpatterns+=router.urls # 一种方式自动生成路由

[View视图层]
from django.shortcuts import render
from rest_framework.viewsets import GenericViewSet
# ViewSetMixin:重写了as_view,路由配置变样了 ,generics.GenericAPIView:只需要配置两东西
from rest_framework.mixins import CreateModelMixin,RetrieveModelMixin,UpdateModelMixin
from api import models
from api import ser

class RegisterView(GenericViewSet,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin): # 因为路由是自动生成的我们这里配置了各种mixin代表着路由自动生成action={'get'='list'}...方法
    queryset = models.User.objects.all()
    serializer_class = ser.UserModelSerializer
    #
假设get请求和post请求,用的序列化类不一样,如何处理
    # 重写get_serializer_class,返回啥,用的序列化类就是啥
    # 注册用的序列化类UserModelSerializer,查询一个用的序列化类是UserReadOnlyModelSerializer
    def get_serializer_class(self):
        print(self.action)  # create,retrieve
        if self.action == 'create':
            return ser.UserModelSerializer
        elif self.action == 'retrieve':
            return ser.UserReadOnlyModelSerializer
        elif self.action == 'update': #
更具不同的序列化器返回不同字段逻辑
            return ser.UserImageModelSerializer
[ser.py序列化器]
from rest_framework import serializers
from api import models
from rest_framework.exceptions import ValidationError


class UserModelSerializer(serializers.ModelSerializer):
    re_password = serializers.CharField(max_length=16, min_length=4, required=True,
                                        write_only=True)  #
因为re_password在表中没有,需要在这定义,而且反序列话不用这个字段给客户看,所以用write_only
    class Meta:
        model = models.User
        fields = ['username', 'password', 'mobile', 're_password', 'icon']
        extra_kwargs = {
            'username': {'max_length': 16},
            'password': {'write_only': True}
        }
    # 局部钩子
    def validate_mobile(self, data):
        if not len(data) == 11:
            raise ValidationError('手机号不合法')
        return data
    def validate(self, attrs):
        if attrs.get('password') == attrs.get('re_password'):
            raise ValidationError('两次密码不一致')
        attrs.pop('re_password')  # 这个字段是自己写的,数据库没有存,我们存放是的时候是**attr直接打散的
        return attrs
    def create(self, validated_data):
        # 如果上面没有剔除re_password可以在validated_date剔除也乐意
        user = models.User.objects.create(**validated_data)
        return user
class UserReadOnlyModelSerializer(serializers.ModelSerializer):
    class Meta:
        models = models.User
        fields =
['username', 'icon']
---------------------------------------------------------------------------------------------------------------------------# 1jwt
[1、控制用户登录后才能访问,不登陆不能访问]
# 可以通过认证类:JSONWebTokenAuthentication和权限类IsAuthenticated,来控制用户登录以后才能访问某一些接口
# 如果用户不登录可以访问,只需要把权限类IsAuthenticated注释掉就可以了
class OrderAPIView(APIView):
    authentication_class =
[JSONWebTokenAuthentication]# 这个负载里面必须有jwt才会进行解析后面的token,要不然后面decode方法时request.user没有东西
    # 权限控制
    permission_classes = [IsAuthenticated]
    def get(self,request,*args,**kwargs):
        return Response('
这是订单信息')
class UserInfoAPIView(APIView):
    authentication_class =
[JSONWebTokenAuthentication]# 内置的jwt匿名用户和登录用户都可以访问
    # 权限控制 在不加这个权限控制的时候匿名用户也可以访问的
    # permission_classes = [IsAuthenticated]
    def get(self,request,*args,**kwargs):
        return Response('
这是订单信息')

[2、控制登录接口返回的数据格式]
    -第一种方案,自己写登录接口
    -第二种写法,用内置,控制登录接口返回的数据格式
       -jwt的配置信息中有这个属性
           'JWT_RESPONSE_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_response_payload_handler',
       -
重写jwt_response_payload_handler,配置成咱们自己的
-----------------------------------------------------------------------------------------
from rest_framework.authentication import BaseAuthentication # 基于它
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication # 基于它
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import jwt_decode_handler
import jwt
from api import models

# 31自定义BaseAuthentication(自定义认证方式)
class MyJwtAuthentication(BaseAuthentication):
    def authenticate(self, request):
        jwt_value=request.META.get('HTTP_AUTHORIZATION')
        if jwt_value:
            # jwt
提供了通过三段token,取出payload的方法,并且有校验功能
            try:
               
payload=jwt_decode_handler(jwt_value)
            except jwt.ExpiredSignature:
                raise AuthenticationFailed('
签名过期')
            except jwt.InvalidTokenError:
                raise AuthenticationFailed('
用户非法')
            except Exception as e:
                raise AuthenticationFailed(str(e))
            print(payload)
            
# 需要返回用户对象 第一种,去数据库查,完成信息都存在的
            # user=models.User.objects.get(pk=payload.get('user_id'))
            # 第二种不查库 速度快,但是对象的信息都是自己手动放进去的,是一个餐费
            user= models.User(id=payload.get('user_id'),username=payload.get('username'))
            return user,jwt_value

        #
没有值,直接抛异常
        raise AuthenticationFailed('你没有携带认证信息')
# 32 基于BaseJSONWebTokenAuthentication内置写好的
class MyJwtAuthentication1(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        
jwt_value=request.META.get('HTTP_AUTHORIZATION')
        if jwt_value:
            # jwt
提供了通过三段token,取出payload的方法,并且有校验功能
            try:
               
payload=jwt_decode_handler(jwt_value)
            except jwt.ExpiredSignature:
                raise AuthenticationFailed('
签名过期')
            except jwt.InvalidTokenError:
                raise AuthenticationFailed('
用户非法')
            except Exception as e:
                raise AuthenticationFailed(str(e))
            print(payload)
            
user=self.authenticate_credentials(payload)
            return user, jwt_value

        #
没有值,直接抛异常
        raise AuthenticationFailed('你没有携带认证信息')
----------------------------------------------------------------------------------------------------
# 4、多种方式登录、手动签发token
1
、使用用户名,手机号,邮箱,都可以登录
# 使用用户名,手机号,邮箱,都可以登录#
# 前端需要传的数据格式
{
"username":"lqz/1332323223/33@qq.com",
"password":"lqz12345"
}
# 视图
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin, ViewSet

from app02 import ser
class Login2View(ViewSet):  #
跟上面完全一样
    def login(self, request, *args, **kwargs):
        # 1
需要 有个序列化的类
        login_ser = ser.LoginModelSerializer(data=request.data,context={'request':request})
        # 2
生成序列化类对象
        # 3 调用序列号对象的is_validad
        login_ser.is_valid(raise_exception=True)
        token=login_ser.context.get('token')
        # 4 return
        return Response({'status':100,'msg':'
登录成功','token':token,'username':login_ser.context.get('username')})
   
# 序列化类(写主要业务逻辑)
from rest_framework import serializers
from api import models
import re
from rest_framework.exceptions import ValidationError

from rest_framework_jwt.utils import jwt_encode_handler,jwt_payload_handler
class LoginModelSerializer(serializers.ModelSerializer):
    username=serializers.CharField()  #
重新覆盖username字段,数据中它是uniquepost,认为你保存数据,自己有校验没过
    class Meta:
        model=models.User
        fields=
['username','password']

    def validate(self, attrs):

        print(self.context)

        # 在这写逻辑
        username=attrs.get('username') # 用户名有三种方式
        password=attrs.get('password')
        # 通过判断,username数据不同,查询字段不一样
        # 正则匹配,如果是手机号
        if re.match('^1[3-9][0-9]{9}$',username):
            user=models.User.objects.filter(mobile=username).first()
        elif re.match('^.+@.+$',username):# 邮箱
            user=models.User.objects.filter(email=username).first()
        elif:
            user=models.User.objects.filter(username=username).first()
        if user: # 存在用户
            # 校验密码,因为是密文,要用check_password
            if user.check_password(password):
                # 签发token
                payload = jwt_payload_handler(user)  # user传入,得到payload
                token = jwt_encode_handler(payload)  # payload传入,得到token
                self.context['token']=token
                self.context['username']=user.username
                return attrs
            else:
                raise ValidationError('密码错误')
        else:
            raise ValidationError('用户不存在')
-----------------------------------------------------------------------------
## 5 jwt的配置过期时间

# jwt的配置
import datetime
JWT_AUTH={
    'JWT_RESPONSE_PAYLOAD_HANDLER':'app02.utils.my_jwt_response_payload_handler',
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), #
过期时间,手动配置
}
--------------------------------------------------------------------------------
# 2 基于角色的权限控制(django内置auth体系)

# RBAC :是基于角色的访问控制(Role-Based Access Control ,公司内部系统
# djangoauth就是内置了一套基于RBAC的权限系统

# django
   # 后台的权限控制(公司内部系统,crmerp,协同平台)
   user
    permssion
    group
    user_groups表是usergroup的中间表
    group_permissions表是grouppermssion中间表
    user_user_permissions表是userpermission中间表
    # 前台(主站),需要用三大认证

# 3 django缓存
# 前端混合开发缓存的使用
   -缓存的位置,通过配置文件来操作(以文件为例)
    -缓存的粒度:
       -全站缓存
           中间件
            MIDDLEWARE = [
                'django.middleware.cache.UpdateCacheMiddleware',
                。。。。
                'django.middleware.cache.FetchFromCacheMiddleware',
            ]
            CACHE_MIDDLEWARE_SECONDS=10  # 全站缓存时间
        -单页面缓存
           在视图函数上加装饰器
            from django.views.decorators.cache import cache_page
            @cache_page(5)  # 缓存5s
            def test_cache(request):
                import time
                ctime=time.time()
                return render(request,'index.html',context={'ctime':ctime})
           
        -页面局部缓存
           {% load cache %}
            {% cache 5 'name' %}  # 5表示5s钟,name是唯一key
             {{ ctime }}
            {% endcache %}
# 前后端分离缓存的使用
   - 如何使用
        from django.core.cache import cache
        cache.set('key',value可以是任意数据类型)
        cache.get('key')
    -应用场景:
       -第一次查询所有图书,你通过多表联查序列化之后的数据,直接缓存起来
        -后续,直接先去缓存查,如果有直接返回,没有,再去连表查,返回之前再缓存

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-1003525-1-1.html 上篇帖子: Django之drf中自定义频率、自动生成接口文档、JWT 下篇帖子: Django之drf回顾
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表