• Django高级篇三。restful的解析器,认证组件,权限组件


    一、rest=framework之解析器

    1)解析器作用。

    根据提交的数据。只解析某些特定的数据。非法数据不接收,为了系统安全问题

    比如解析的数据格式有

    有application/json,x-www-form-urlencoded,form-data等格式

    默认支持的数据类型

    'rest_framework.parsers.JSONParser'
    'rest_framework.parsers.FormParser'
    'rest_framework.parsers.MultiPartParser'

    2)解析器局部配置

    定义路由:url(r'^books/', views.Book.as_view()),

    视图函数配置

    from rest_framework.parsers import JSONParser   # 只能解析json格式
    class Book(APIView):
        parser_classes = [JSONParser, ]     # 如果加上这行只支持json格式,不加都支持
        def get(self,request,*args,**kwargs):
            return HttpResponse('OK')
        def post(self,request):
            print(request.data)
            return HttpResponse('post') 
    View Code

    实例

    说明不支持该格式

    2)全局配置。在settings.py的最后加入配置,一般实际工作中,都使用json格式

    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser'  
            #'rest_framework.parsers.FormParser'
            #'rest_framework.parsers.MultiPartParser'
        ]}

    视图函数,则不需要再添加了

    3)全局配置+局部配置

    解析器查询顺序,先从本地函数==》settings.py配置 ===》系统函数

    即某函数需要用多个解析器,则单独配置,就不走全局配置了

     二、rest=framework之认证组件

    1)用户登录测试

    1.1)先创建用户表

    # 认证的表
    class User(models.Model):
        nid = models.AutoField(primary_key=True)
        name= models.CharField(max_length=32)
        pwd=models.CharField(max_length=32,null=True)
    
    class UserToken(models.Model):
        user = models.OneToOneField(to=User,to_field='nid')
        token=models.CharField(max_length=64)
    用户认证相关表

    1.2)定义路由系统

    url(r'^login/', views.Login.as_view()),

    1.3)创建视图函数

    # 认证组件
    import hashlib,time
    def get_token(username):
        md = hashlib.md5()
        md.update(username.encode('utf-8'))
        md.update(str(time.time()).encode('utf-8'))
        return md.hexdigest()
    
    class Login(APIView):
        def post(self,requeset):
            response = MyResponse()
            name = requeset.data.get('name')
            pwd = requeset.data.get('pwd')
            user = models.User.objects.filter(name=name,pwd=pwd).first()
            if user:
                response.msg='登陆成功'
                # 需要生成一个随机字符串
                token=get_token(name)
                response.token=get_token(name)
                # 吧随机字符串保存到数据库
                #ret = models.UserToken.objects.update_or_create(user_id=user.id,kwargs={'token':token})    # 都可以
                ret = models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
            else:
                response.msg='用户名或密码错误'
                response.status=101
            return JsonResponse(response.get_dic)
    class Login

    1.4)登录测试

    2)用户登录之后才能访问数据测试

    2.1)查看定义的路由

    url(r'^books/', views.Book.as_view()),
    url(r'^login/', views.Login.as_view()),

    2.2)查看自己定义的序列化组件

    from rest_framework import serializers
    from app01 import models
    
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            exclude=['authors']
        name = serializers.CharField(error_messages={'required':'该字段必填'})
    myserial.py

    2.3)创建视图函数

    # 认证组件
    import hashlib,time
    def get_token(username):
        md = hashlib.md5()
        md.update(username.encode('utf-8'))
        md.update(str(time.time()).encode('utf-8'))
        return md.hexdigest()
    
    class Login(APIView):
        def post(self,requeset):
            response = MyResponse()
            name = requeset.data.get('name')
            pwd = requeset.data.get('pwd')
            user = models.User.objects.filter(name=name,pwd=pwd).first()
            if user:
                response.msg='登陆成功'
                # 需要生成一个随机字符串
                token=get_token(name)
                response.token=get_token(name)
                # 吧随机字符串保存到数据库
                #ret = models.UserToken.objects.update_or_create(user_id=user.id,kwargs={'token':token})    # 都可以
                ret = models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
            else:
                response.msg='用户名或密码错误'
                response.status=101
            return JsonResponse(response.get_dic)
    
    from app01 import myserial
    class Book(APIView):
        def get(self,request):
            # 必须登录才能反问数据库
            # token = request.GET.get('token')
            token = request.query_params.get('token')
            ret = models.UserToken.objects.filter(token=token).first()
            response = MyResponse()
            if ret:
                books=models.Book.objects.all()
                ret = myserial.BookSer(instance=books,many=True)
                response.msg = '查询成功'
                response.data=ret.data
            else:
                response.msg = '没有登录'
                response.status=101
            return JsonResponse(response.get_dic,safe=False)
    Class Login and Books

    2.4)登录测试

     3)抽取验证是否登录功能,测试(减少重复验证登录的代码冗余)

    只修改了视图函数的方法

    import hashlib,time
    def get_token(username):
        md = hashlib.md5()
        md.update(username.encode('utf-8'))
        md.update(str(time.time()).encode('utf-8'))
        return md.hexdigest()
    
    class Login(APIView):
        def post(self,requeset):
            response = MyResponse()
            name = requeset.data.get('name')
            pwd = requeset.data.get('pwd')
            user = models.User.objects.filter(name=name,pwd=pwd).first()
            if user:
                response.msg='登陆成功'
                token=get_token(name)
                response.token=get_token(name)
                ret = models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
            else:
                response.msg='用户名或密码错误'
                response.status=101
            return JsonResponse(response.get_dic)
    
    from rest_framework.exceptions import AuthenticationFailed
    class myAuthen():
        def authenticate(self,request):
            token=request.query_params.get('token')
            ret = models.UserToken.objects.filter(token=token).first()
            if ret:
                return ret.user,ret
            else:
                raise AuthenticationFailed('您没有登录')
        def authenticate_header(self,value):
            # 该函数一定要写
            pass
    
    from app01 import myserial
    class Book(APIView):
        authentication_classes = [myAuthen,]
        def get(self,request):
            response = MyResponse()
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    View Code

     3.1)调试模式,打印输出登录的用户,即携带的token

    from app01 import myserial
    class Book(APIView):
        authentication_classes = [myAuthen,]
        def get(self,request):
            response = MyResponse()
            print(request.user.name)    # 打印用户
            print(request.auth.token)   # 携带的token
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)

     3.2)处理 该函数 authenticate_header 内容为pass 的问题。需要继承 BaseAuthentication 才可删除该无用函数

    完善认证组件代码

    import hashlib,time
    def get_token(username):
        md = hashlib.md5()
        md.update(username.encode('utf-8'))
        md.update(str(time.time()).encode('utf-8'))
        return md.hexdigest()
    
    class Login(APIView):
        def post(self,requeset):
            response = MyResponse()
            name = requeset.data.get('name')
            pwd = requeset.data.get('pwd')
            user = models.User.objects.filter(name=name,pwd=pwd).first()
            if user:
                response.msg='登陆成功'
                token=get_token(name)
                response.token=get_token(name)
                ret = models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
            else:
                response.msg='用户名或密码错误'
                response.status=101
            return JsonResponse(response.get_dic)
    
    from rest_framework.exceptions import AuthenticationFailed
    from rest_framework.authentication import BaseAuthentication
    class myAuthen(BaseAuthentication):
        def authenticate(self,request):
            token=request.query_params.get('token')
            ret = models.UserToken.objects.filter(token=token).first()
            if ret:
                return ret.user,ret
            else:
                raise AuthenticationFailed('您没有登录')
    
    from app01 import myserial
    class Book(APIView):
        authentication_classes = [myAuthen,]
        def get(self,request):
            response = MyResponse()
            print(request.user.name)    # 打印用户
            print(request.auth.token)   # 携带的token
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    View Code

     3.3)认证组件总结

    作用:校验是否登录
    首先定义一个类,继承BaseAuthentication,写一个方法authenticate,在方法内部实现认证过程,
    认证通过,返回None或者两个对象(user,auth),在视图类的request中可以取出来。这2个对象也可以是任意2个对象
    
    from rest_framework.authentication import BaseAuthentication
    class myAuthen(BaseAuthentication):
        def authenticate(self,request):
            token=request.query_params.get('token')
            ret = models.UserToken.objects.filter(token=token).first()
            if ret:
                # return ret.user, ret
                # 要写多个认证类,这个的返回None
                # 最后一个认证类,返回这俩值       
                return ret.user,ret
            else:
                raise AuthenticationFailed('您没有登录')
    
    局部使用:在视图类中(可以写多个)
        authentication_classes = [myAuthen,]
    全局使用:在settings.py中写入
        注意:1、全局使用时,认证组件不可以放在视图函数内
             2、写了全局,局部就要删掉
             3、在登录函数中,也会走认证组件,而登录是不要认证的
                需要在登录中添加:authentication_classes = []
                class Login(APIView):
                    authentication_classes = []
                    def post(self,requeset):
                        ......

    全局使用实例

    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser'
            # 'rest_framework.parsers.FormParser'
            # 'rest_framework.parsers.MultiPartParser'
        ],
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.views.myAuthen",]
    }

    token不存数据库方式,请参照

    原文链接:https://www.cnblogs.com/liuqingzheng/articles/9766397.html

     二、rest=framework之权限组件

    作用:校验用户是否有权限访问
    因为是在认证通过才执行的,所以可以取出user

    创建类

    class User(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        pwd=models.CharField(max_length=32,null=True)
        mychoice=((1,'普通用户'),(2,'超级用户'),(3,'宇宙用户'))
        usertyle=models.IntegerField(choices=mychoice,default=1)
    mychoice选择类型

    2.1)定义权限组件

    # 权限组件
    class myPermission():
        message = '不是超超级用户,查看不了'
        def has_permission(self,request,view):
            print(request.user.usertype)
            if request.user.usertype !=3:
                return False
            else:
                return True

    使用和认证组件的方法一样,只是要写在认证组件之后

    from app01 import myserial
    from app01.auth import myPermission
    class Book(APIView):
        authentication_classes = [myAuthen,]
        permission_classes = [myPermission,]
        def get(self,request):
            response = MyResponse()
            # print(request.user.name)    # 打印用户
            # print(request.auth.token)   # 携带的token
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    视图

     2.2)继承权限:from rest_framework.permissions import BasePermission

    from rest_framework.permissions import BasePermission
    class myPermission(BasePermission):
        message = '不是超超级用户,查看不了'
        def has_permission(self,request,view):
            print(request.user.usertype)
            if request.user.usertype !=1:
                return False
            else:
                return True
    class myPermission
  • 相关阅读:
    VS2010 VC Project的default Include设置
    Linux 下的编辑/编译器
    用命令实现Win7远程桌面关机和重启
    怎样快速刪除Word中超链接?
    chrome浏览器世界之窗浏览器的收藏夹在哪?
    代码量查找工具[最好用的]
    C项目实践--网络协议和套接字编程
    memmove 和 memcopy
    bzoj2456: mode
    bzoj1205: [HNOI2005]星际贸易
  • 原文地址:https://www.cnblogs.com/linu/p/10080437.html
Copyright © 2020-2023  润新知