首页 > 技术文章 > Rest-framework之drf认证组件,权限组件+不存数据库的token认证

cao123 2018-12-13 21:13 原文

  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-登录接口

 

推荐阅读