zoukankan      html  css  js  c++  java
  • Rest-framework之drf认证组件,权限组件+不存数据库的token认证

      Rest-framework之drf认证组件,权限组件

    django中一个请求时一个reques,如果在哪个位置改了request,那么到了后面就是修改过的request
    昨日回顾:
    认证:
    -写一个认证类,(可以继承BaseAuthentication)
    -注意:这个类要放在单独的py文件中,(如果放在view中,全局配置无法使用)
    -类中写个函数:def authenticate(self,request)
    -认证的判断:
    -取出token做验证
    -验证通过,可以返回两个值,一个给了request.user,一个给了request.auth
    -验证不通过,抛异常
    -因为认证类可以写多个,如果想让多个都执行,放在前面的不能return值
    -局部使用:
    -在视图类中
    authentication_classes = [LoginAuth, ]
    -全局使用:
    -在setting中配置
    -REST_FRAMEWORK={
    'DEFAULT_AUTHENTICATION_CLASSES':['app01.MyAuth.LoginAuth',],
    }
    -局部禁用:
    -在视图类中
    authentication_classes = [ ]
    权限:
    -写一个权限类,(可以继承BasePermission)
    -注意:这个类要放在单独的py文件中,(如果放在view中,全局配置无法使用)
    -类中的方法:def has_permission(self,request,view)
    -认证通过:返回True
    -认证不通过:返回False
    -返回值:布尔类型
    -局部使用:
    -在视图类中:
    -permission_classes = [UserPermission,]
    -全局使用:
    -在setting中配置
    -REST_FRAMEWORK={
    'DEFAULT_PERMISSION_CLASSES':['app01.MyAuth.UserPermission',]
    }
    -局部禁用:
    -在视图类中:
    -permission_classes = []

    choice的用法:
    -拿出数字对应的中文:get_字段名_dispaly()
    
    
     因为认证类可以写多个,如果想要多个都执行,放在前面的就不能return值,可以return None

    1.views视图层

    from django.shortcuts import render
    from rest_framework.views import APIView
    from app01 import models
    from django.core.exceptions import ObjectDoesNotExist
    import hashlib
    import time
    from django.http import JsonResponse
    from app01 import MySerializer
    from rest_framework.request import Request
    from rest_framework import exceptions
    
    def get_token(name):
        md5 = hashlib.md5()  # 生成一个MD5对象
        # 往里添加值,必须是bytes格式
        # time.time()生成时间戳类型,转成字符串,再encode转成bytes格式
        md5.update(str(time.time()).encode('utf-8'))
        md5.update(name.encode('utf-8'))
        return md5.hexdigest()
    
    
    # 登录接口
    class Login(APIView):
        authentication_classes = []
    
        # 登录就是使用post,get是返回一个页面
        def post(self, request, *args, **kwargs):
            response = {'status': 100, 'msg': '登录成功'}
            name = request.data.get('name')
            pwd = request.data.get('pwd')
            try:
                user = models.UserInfo.objects.get(name=name, pwd=pwd)
                # 校验通过,登陆成功,就生成一个随机字符串(身份标识),token
                token = get_token(name)
                # 保存到数据库
                # user=user就是需要查询的数据,defaults里面:token就是需要修改或者新增的数据
                models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
                # 登陆成功之后把登录返回给他,以后就带着token过来
                response['token'] = token
            except ObjectDoesNotExist as e:
                response['status'] = 101
                response['msg'] = '用户名或密码错误'
    
            except Exception as e:
                # 万能异常,里面只要出错,程序就会走到这里
                response['status'] = 102
                # response['msg'] = '未知错误'
                # 把整个错误信息转换成str类型,赋值给e,一般在测试时使用这个
                response['msg'] = str(e)
                # 如果不写safe=False,只能序列化字典形式,如果字典里面又套了列表,或者直接是一个列表,就必须写safe=False
            return JsonResponse(response, safe=False)
    
    
    from app01.MyAuth import LoginAuth
    
    class Books(APIView):
        # 列表中类名不能加括号
        authentication_classes = [LoginAuth, ]
    
        def get(self, request, *args, **kwargs):
            # 只要通过认证,就能取到当前登录用户对象的密码,id等信息
            # print(request.query_params)
            # print(request.user.name)
            # print(request.user.pwd)
            response = {'status': 100, 'msg': '查询成功'}
            res = models.Book.objects.all()
            book_ser = MySerializer.BookSerializer(res, many=True)
            # 这个数据是需要返回给前台的
            response['data'] = book_ser.data
            # print(book_ser.data)
            return JsonResponse(response, safe=False)
    
    
    # 需求:只能黄金会员才能查看作者详情,其他会员不能看
    from app01.MyAuth import UserPermission
    
    class Authors(APIView):
        # permission_classes = [UserPermission,]
        # 局部禁用
        permission_classes = []
    
        def get(self, request, *args, **kwargs):
            response = {'status': 100, 'msg': '查询成功'}
            author_all = models.Author.objects.all()
            author_ser = MySerializer.AuthorSerializer(author_all, many=True)
            response['data'] = author_ser.data
            return JsonResponse(response, safe=False)
    
    
    class User(APIView):
        def get(self, request, *args, **kwargs):
            response = {'status': 100, 'msg': '查询成功'}
            user_all = models.UserInfo.objects.all()
            user_ser = MySerializer.UserSerializer(user_all, many=True)
            response['data'] = user_ser.data
            return JsonResponse(response, safe=False)
    View Code

    2.MyAuth.py-认证组件和权限组件

    from app01 import models
    from rest_framework import exceptions
    from rest_framework.authentication import BaseAuthentication
    
    
    # 认证组件,使用drf的认证,我们需要写一个类
    class LoginAuth(BaseAuthentication):
        # 函数名一定要叫authenticate,需要接收2个参数,第二个参数是request对象
        def authenticate(self, request):
            # 从request对象中取出token(也可以从其他地方取)
            token = request.query_params.get('token')
            # 去数据库过滤,查询
            ret = models.UserToken.objects.filter(token=token).first()
            if ret:
                # 能查到,说明认证通过,反回空
                # ret.user就是当前登录用户对象
                return ret.user, ret
            # 如果查不到,就抛出异常
            raise exceptions.APIException('认证失败')
    
    
    #权限组件,谁有资格查看作者详情信息
    class UserPermission():
        # message是错误显示的中文
        message = '您没有权限查看'
    
        def has_permission(self, request, view):
            user_type = request.user.user_type
            # print(user_type)
            # 取出用户类型对应的文字
            # 固定用法:get_字段名_display()
            user_type_name = request.user.get_user_type_display()
            print(user_type_name)
            if user_type == 2:
                return True
            else:
                return False
    View Code

    3.MySerializer.py-序列化组件

    from rest_framework import serializers
    from app01 import models
    
    
    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = '__all__'
    
    
    class AuthorSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Author
            fields = '__all__'
    
    
    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = '__all__'
    
        user_type=serializers.CharField(source='get_user_type_display')
        # user_type = serializers.SerializerMethodField()
    
        # def get_user_type(self, obj):
        #     return obj.get_user_type_display()
    View Code

    4.models层

    from django.db import models
    
    
    # Create your models here.
    # 用户信息
    class UserInfo(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        # 写choice
        user_choice = ((0, '普通会员'), (1, '铂金会员'), (2, '黄金会员'))
        # 指定choice,可以快速的通过数字,取出文字
        user_type = models.IntegerField(choices=user_choice,default=0)
    
    
    # 用户token
    class UserToken(models.Model):
        token = models.CharField(max_length=64)
        user = models.OneToOneField(to='UserInfo')
    
    
    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish_date = models.DateField()
    
        publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)  # 删除关联数据,与之关联也删除
        authors = models.ManyToManyField(to='Author')
    
        def __str__(self):
            return self.name
    
    
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_detail = models.OneToOneField(to='AuthorDetail', to_field='nid', unique=True, on_delete=models.CASCADE)
    
    
    class AuthorDetail(models.Model):
        nid = models.AutoField(primary_key=True)
        telephone = models.BigIntegerField()
        birthday = models.DateField()
        addr = models.CharField(max_length=64)
    
        def __str__(self):
            return self.telephone
    
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
    
        def __str__(self):
            return self.name
    
        def test(self):
            return self.email
    View Code

    5.settings.py

    全局使用认证和权限
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': ['app01.MyAuth.LoginAuth', ],
        'DEFAULT_PERMISSION_CLASSES': ['app01.MyAuth.UserPermission', ]
    }

     6.urls.py路由层

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login/', views.Login.as_view()),
        url(r'^books/', views.Books.as_view()),
        url(r'^authors/', views.Authors.as_view()),
        url(r'^users/', views.User.as_view()),
    ]
    View Code

     7.不存数据库的token认证

    粗糙的丸子
    
    博客园
    首页
    新随笔
    联系
    订阅
    管理
    随笔 - 18  文章 - 2  评论 - 0 
    哇哇哇哇 
    
    1.不存数据库的token认证
     
    
    import hashlib
    from day98 import settings
    
    
    def check_token(token):
        ret = True
        user_info = None
        try:
            ll = token.split('|')
            # da89744b701b5d8bc5b9a76b4ddb3dd4 , {"name": "cao", "id": 1},已经切分成了一个列表
            md5 = hashlib.md5()
            # 需要给这个{"name": "cao", "id": 1}加密,它就是列表里的第一个值
            md5.update(ll[1].encode('utf-8'))
            # 在setting里面全局配置一下,给token加盐
            md5.update(settings.password.encode('utf-8'))
            # hex=da89744b701b5d8bc5b9a76b4ddb3dd4
            hex = md5.hexdigest()
            if not hex == ll[0]:
                ret = False
            else:
                user_info = ll[1]
        except Exception as e:
            ret = False
        return ret, user_info
    
    
    class LoginAuth(BaseAuthentication):
        # 函数名一定要叫authenticate,需要接收2个参数,第二个参数是request对象
        def authenticate(self, request):
            # 从request对象中取出token(也可以从其他地方取)
            token = request.query_params.get('token')
            # ret是布尔类型,表示验证通过或者失败,user_info是user的字典
            ret, user_info = check_token(token)
            if ret:
                # 能查到,说明认证通过,反回空
                # ret.user就是当前登录用户对象
                return user_info, None
            # 如果查不到,就抛出异常
            raise exceptions.APIException('认证失败')
    
     View.py-登录接口
     
    
    
    
    好文要顶 关注我 收藏该文   
    
    粗糙的丸子
    关注 - 6
    粉丝 - 0 
    
    
    
    0 
    0 
    
    
    
    « 上一篇:Rest-framework之drf认证组件,权限组件
    posted @ 2018-12-14 16:45 粗糙的丸子 阅读(0) 评论(0) 编辑 收藏
    
    
    刷新评论刷新页面返回顶部
    发表评论
    昵称: 
    评论内容:
          
    
     
     退出 
    
    [Ctrl+Enter快捷键提交] 
    
    【推荐】超50万VC++源码: 大型组态工控、电力仿真CAD与GIS源码库!
    【活动】华为云12.12会员节全场1折起 满额送Mate20
    【活动】华为云会员节云服务特惠1折起
    【活动】腾讯云+社区开发者大会12月15日首都北京盛大起航!
    
    
    相关博文:
    · 哇哇cool~~~
    · 呜哇哇,呜嘛嘛
    · 哇哇哇~~
    · Linux常用命令大全
    · java网络编程Socket通信详解
    
    最新新闻:
    · 消失的90后CEO与赌场资本主义年代
    · 从孟晚舟职场二三事说起
    · 微软可穿戴设备专利曝光:有望改善帕金森患者手部的颤抖影响
    · 知乎架构调整:提高组织力 任命前蜜芽合伙人为CFO
    · Apple Music有个功能被苹果砍掉了,但你可能从未用过它
    » 更多新闻...
    
    公告
     
    github com/粗糙的丸子 
    邮箱: 2120176410@gq.com 
    微信(QQ) : 2120176410
    昵称:粗糙的丸子
    园龄:4个月
    粉丝:0
    关注:6
    
    <
    2018年12月
    >
    日
    一
    二
    三
    四
    五
    六
    25
    26
    27
    28
    29
    30
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    1
    2
    3
    4
    5
    搜索
     
     
    常用链接
    我的随笔
    我的评论
    我的参与
    最新评论
    我的标签
    
    随笔档案
    2018年12月 (5) 
    2018年11月 (5) 
    2018年10月 (1) 
    2018年9月 (7) 
    2018年8月 (1) 
    
    阅读排行榜
    1. 小红书要求的技能掌握(熟悉RESTful服务,深刻理解mvc,oop, Aop概念)(29)
    2. python题目-----search()和match()的区别(19)
    3. mysql表操作之完整性约束(18)
    4. css的三大特性继承性,层叠行,优先级(17)
    5. Json模块dumps、loads、dump、load函数介绍(16)
    
    
    
    
    Copyright ©2018 粗糙的丸子 
    MyAuth.py-认证组件
    class Books(APIView):
        # 列表中类名不能加括号
        authentication_classes = [LoginAuth, ]
    
        def get(self, request, *args, **kwargs):
            # 只要通过认证,就能取到当前登录用户对象的密码,id等信息
            # print(request.query_params)
            print(request.user)
            # print(request.user.pwd)
            response = {'status': 100, 'msg': '查询成功'}
            res = models.Book.objects.all()
            book_ser = MySerializer.BookSerializer(res, many=True)
            # 这个数据是需要返回给前台的
            response['data'] = book_ser.data
            # print(book_ser.data)
            return JsonResponse(response, safe=False)
    
    
    # 登录接口,不存数据库的token认证
    import json
    
    from day98 import settings
    
    
    def create_token(user_pk):
        md5 = hashlib.md5()
        md5.update(user_pk.encode('utf-8'))
        # 在setting里面全局配置一下,给token加盐
        md5.update(settings.password.encode('utf-8'))
        hex = md5.hexdigest()
        token = '|'.join([hex, user_pk])
        # token=hex+'|'+user_info
        print(token)
        return token
    
    
    class Login(APIView):
        authentication_classes = []
    
        # 登录就是使用post,get是返回一个页面
        def post(self, request, *args, **kwargs):
            response = {'status': 100, 'msg': '登录成功'}
            name = request.data.get('name')
            pwd = request.data.get('pwd')
            try:
                user = models.UserInfo.objects.get(name=name, pwd=pwd)
                user_info_json = json.dumps({'name': user.name, 'id': user.pk})
                # 生成vfvevberber|{'name': user.name, 'id': user.pk}的token
                token = create_token(str(user.pk))
                # 登陆成功之后把登录返回给他,以后就带着token过来
                response['token'] = token
            except ObjectDoesNotExist as e:
                response['status'] = 101
                response['msg'] = '用户名或密码错误'
    
            except Exception as e:
                # 万能异常,里面只要出错,程序就会走到这里
                response['status'] = 102
                # response['msg'] = '未知错误'
                # 把整个错误信息转换成str类型,赋值给e,一般在测试时使用这个
                response['msg'] = str(e)
                # 如果不写safe=False,只能序列化字典形式,如果字典里面又套了列表,或者直接是一个列表,就必须写safe=False
            return JsonResponse(response, safe=False)
    
    View.py-登录接口
    View.py-登录接口
  • 相关阅读:
    加密算法 科普文
    《电商后台系统产品逻辑解析》学习笔记
    基于Docker的Consul服务发现集群搭建
    从阿里中台战略看企业IT架构转型之道
    CanalSharp.AspNetCore v0.0.4-支持输出到MongoDB
    领域驱动设计学习之路—DDD的原则与实践
    一个实时收集MySql变更记录的组件CanalSharp.AspNetCore
    基于Jenkins Pipeline的ASP.NET Core持续集成实践
    熊逸《唐诗50讲》感时篇
    一个Mini的ASP.NET Core框架的实现
  • 原文地址:https://www.cnblogs.com/cao123/p/10116473.html
Copyright © 2011-2022 走看看