drf认证组件

(1)model层

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    # 写choice
    user_choice = ((0, '普通用户'), (1, '会员'), (2, '超级用户'))
    # 指定choice,可以快速的通过数字,取出文字使用get_user_type_display()
    user_type = models.IntegerField(choices=user_choice, default=0)
    pwd = models.CharField(max_length=32)


# 用户token
class UserToken(models.Model):
    token = models.CharField(max_length=64)
    user = models.OneToOneField(to=UserInfo)
    

(2)新建认证类(验证通过return两个参数)

from app01 import models
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication


# 用drf的认证,写一个类
class LoginAuth(BaseAuthentication):
    # 函数名一定要叫authenticate,接收必须两个参数,第二个参数是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('您认证失败')

(3)view层

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 import exceptions

def get_token(name):
    # 生成一个md5对象
    md5 = hashlib.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 = []
    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)
            # 保存到数据库
            # update_or_create更新或者创建
            models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
            response['token'] = token
        except ObjectDoesNotExist as e:
            response['status'] = 101
            response['msg'] = '用户名或密码错误'
        except Exception as e:
            response['status'] = 102
            # response['msg']='未知错误'
            response['msg'] = str(e)
        return JsonResponse(response, safe=False)


from rest_framework.request import Request
from app01.MyAuth import LoginAuth
class Books(APIView):
    #-局部使用,在视图类中加一行:
    # 列表中,类名不能加括号
    # authentication_classes = [LoginAuth, ]

    def get(self, request, *args, **kwargs):
        # 只要通过认证,就能取到当前登录用户对象
        print(request.user)
        response = {'status': 100, 'msg': '查询成功'}
        ret = models.Book.objects.all()
        book_ser = MySerializer.BookSerializer(ret, many=True)
        response['data'] = book_ser.data
        return JsonResponse(response, safe=False)



-全局使用
    -在setting中配置:
      REST_FRAMEWORK={
         'DEFAULT_AUTHENTICATION_CLASSES':['app01.MyAuth.LoginAuth',]
       }
        

 不存数据库的认证

from day98 import settings


def create_token(user_id):
    md5 = hashlib.md5()
    md5.update(user_id.encode('utf-8'))
    md5.update(settings.password.encode('utf-8'))
    hex = md5.hexdigest()
    token = hex + '|' + user_id
    print(token)
    return token


# 登录
class Login(APIView):
    authentication_classes = []

    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})
            # 生产dafgasdewf|{'name':user.name,'id':user.pk}的token
            token = create_token(str(user.pk))
            # 保存到数据库
            # update_or_create更新或者创建
            response['token'] = token
        except ObjectDoesNotExist as e:
            response['status'] = 101
            response['msg'] = '用户名或密码错误'
        except Exception as e:
            response['status'] = 102
            # response['msg']='未知错误'
            response['msg'] = str(e)
        return JsonResponse(response, safe=False)


class Books(APIView):
    # 列表中,类名不能加括号
    authentication_classes = [LoginAuth, ]

    def get(self, request, *args, **kwargs):
        # 只要通过认证,就能取到当前登录用户对象
        print(request.user)
        response = {'status': 100, 'msg': '查询成功'}
        ret = models.Book.objects.all()
        book_ser = MySerializer.BookSerializer(ret, many=True)
        response['data'] = book_ser.data
        return JsonResponse(response, safe=False)
import hashlib
from day98 import settings


def check_token(token):
    ret = True
    user_info = None
    try:
        ll = token.split('|')
        # "eef48b787e24381258aa71d0d53615c2,{\"name\": \"lqz\", \"id\": 1}"
        md5 = hashlib.md5()
        md5.update(ll[1].encode('utf-8'))
        md5.update(settings.password.encode('utf-8'))
        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,接收必须两个参数,第二个参数是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:
            return user_info, None
        # 如果查不到,抛异常
        raise exceptions.APIException('您认证失败')
发送post请求:http://127.0.0.1:8000/login/
发送get请求:http://127.0.0.1:8000/books/?token=2cfd4560539f887a5e420412b370b361|1

 

posted @ 2018-12-13 19:13  liweiwei0307  阅读(166)  评论(0编辑  收藏  举报