(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