目录

生鲜超市(一)    生鲜超市(二)    生鲜超市(三)

生鲜超市(四)    生鲜超市(五)    生鲜超市(六)

生鲜超市(七)    生鲜超市(八)    生鲜超市(九)

生鲜超市(十)    生鲜超市(十一)    生鲜超市(十二)    生鲜超市(十三)

代码下载

github

教程

学习自慕课网-前端vue结合后端DjangoFramework的在线生鲜超市

七、用户登录与手机注册

7.1.drf的token

(1)INSTALL_APP中添加

INSTALLED_APPS = (...'rest_framework.authtoken'
)

token会生成一张表authtoken_token,所以要运行migrations和migrate

(2)url配置

from rest_framework.authtoken import viewsurlpatterns = [# tokenpath('api-token-auth/', views.obtain_auth_token)
]

(3)postman发送数据

token值会保存到数据中,跟这个用户相关联

(4)客户端身份验证

对于客户端进行身份验证,令牌密钥应包含在 Authorization HTTP header 中。关键字应以字符串文字 “Token” 为前缀,用空格分隔两个字符串。例如:

Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

注意: 如果您想在 header 中使用不同的关键字(例如 Bearer),只需子类化 TokenAuthentication 并设置 keyword 类变量。

如果成功通过身份验证,TokenAuthentication 将提供以下凭据。

  • request.user 是一个 Django User 实例.
  • request.auth 是一个 rest_framework.authtoken.models.Token 实例.

未经身份验证的响应被拒绝将导致 HTTP 401 Unauthorized 的响应和相应的 WWW-Authenticate header。例如:

WWW-Authenticate: Token

要想获取request.user和request.auth还要在settings中添加

REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.BasicAuthentication','rest_framework.authentication.SessionAuthentication','rest_framework.authentication.TokenAuthentication')
}

drf的token缺点

  • 保存在数据库中,如果是一个分布式的系统,就非常麻烦
  • token永久有效,没有过期时间。

7.2.json web token方式完成用户认证

使用方法:http://getblimp.github.io/django-rest-framework-jwt/

(1)安装

pip install djangorestframework-jwt

(2)使用

REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.BasicAuthentication','rest_framework.authentication.SessionAuthentication','rest_framework_jwt.authentication.JSONWebTokenAuthentication',)
}

(3)url

 # jwt的token认证接口path('jwt-auth/', obtain_jwt_token )

(4)postman

post形式:http://127.0.0.1:8000/jwt-auth/

Now in order to access protected api urls you must include the Authorization: JWT <your_token> header.

$ curl -H "Authorization: JWT <your_token>" http://localhost:8000/protected-url/

7.3.vue和jwt接口调试

vue中登录接口是login

//登录
export const login = params => {return axios.post(`${local_host}/login/`, params)
}

后台的接口跟前端要一致

urlpatterns = [# jwt的认证接口path('login/', obtain_jwt_token )
]

现在就可以登录了

jwt接口它默认采用的是用户名和密码登录验证,如果用手机登录的话,就会验证失败,所以我们需要自定义一个用户验证

 自定义用户认证

(1)settings中配置

AUTHENTICATION_BACKENDS = ('users.views.CustomBackend',)

(2)users/views.py

# users.views.pyfrom django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import QUser = get_user_model()class CustomBackend(ModelBackend):"""自定义用户验证"""def authenticate(self, username=None, password=None, **kwargs):try:#用户名和手机都能登录user = User.objects.get(Q(username=username) | Q(mobile=username))if user.check_password(password):return userexcept Exception as e:return None

(3)JWT有效时间设置

settings中配置

import datetime
#有效期限
JWT_AUTH = {'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),    #也可以设置seconds=20'JWT_AUTH_HEADER_PREFIX': 'JWT',                       #JWT跟前端保持一致,比如“token”这里设置成JWT
}

7.4.云片网发送短信验证码

(1)注册

“开发认证”-->>“签名管理”-->>“模板管理”

还要添加iP白名单,测试就用本地ip,部署的时候一定要换成服务器的ip

(2)发送验证码

apps下新建utils文件夹。再新建yunpian.py,代码如下:

# apps/utils/yunpian.pyimport requests
import jsonclass YunPian(object):def __init__(self, api_key):self.api_key = api_keyself.single_send_url = "https://sms.yunpian.com/v2/sms/single_send.json"def send_sms(self, code, mobile):#需要传递的参数parmas = {"apikey": self.api_key,"mobile": mobile,"text": "【慕雪生鲜超市】您的验证码是{code}。如非本人操作,请忽略本短信".format(code=code)}response = requests.post(self.single_send_url, data=parmas)re_dict = json.loads(response.text)return re_dictif __name__ == "__main__":#例如:9b11127a9701975c734b8aee81ee3526yun_pian = YunPian("2e87d1xxxxxx7d4bxxxx1608f7c6da23exxxxx2")yun_pian.send_sms("2018", "手机号码")

7.5.drf实现发送短信验证码接口

手机号验证:

  • 是否合法
  • 是否已经注册

(1)settings.py

# 手机号码正则表达式
REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"

(2)users下新建serializers.py,代码如下:

# users/serializers.pyimport re
from datetime import datetime, timedelta
from MxShop.settings import REGEX_MOBILE
from users.models import VerifyCode
from rest_framework import serializers
from django.contrib.auth import get_user_model
User = get_user_model()class SmsSerializer(serializers.Serializer):mobile = serializers.CharField(max_length=11)#函数名必须:validate + 验证字段名def validate_mobile(self, mobile):"""手机号码验证"""# 是否已经注册if User.objects.filter(mobile=mobile).count():raise serializers.ValidationError("用户已经存在")# 是否合法if not re.match(REGEX_MOBILE, mobile):raise serializers.ValidationError("手机号码非法")# 验证码发送频率#60s内只能发送一次one_mintes_ago = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)if VerifyCode.objects.filter(add_time__gt=one_mintes_ago, mobile=mobile).count():raise serializers.ValidationError("距离上一次发送未超过60s")return mobile

(3)APIKEY加到settings里面

#云片网APIKEY
APIKEY = "xxxxx327d4be01608xxxxxxxxxx"

(4)views后台逻辑

我们要重写CreateModelMixin的create方法,下面是源码:

class CreateModelMixin(object):"""Create a model instance."""def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)self.perform_create(serializer)headers = self.get_success_headers(serializer.data)return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)def perform_create(self, serializer):serializer.save()def get_success_headers(self, data):try:return {'Location': str(data[api_settings.URL_FIELD_NAME])}except (TypeError, KeyError):return {}

需要加上自己的逻辑

users/views.py

from rest_framework.mixins import CreateModelMixin
from rest_framework import viewsets
from .serializers import SmsSerializer
from rest_framework.response import Response
from rest_framework import status
from utils.yunpian import YunPian
from MxShop.settings import APIKEY
from random import choice
from .models import VerifyCodeclass SmsCodeViewset(CreateModelMixin,viewsets.GenericViewSet):'''手机验证码'''serializer_class = SmsSerializerdef generate_code(self):"""生成四位数字的验证码"""seeds = "1234567890"random_str = []for i in range(4):random_str.append(choice(seeds))return "".join(random_str)def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)#验证合法serializer.is_valid(raise_exception=True)mobile = serializer.validated_data["mobile"]yun_pian = YunPian(APIKEY)#生成验证码code = self.generate_code()sms_status = yun_pian.send_sms(code=code, mobile=mobile)if sms_status["code"] != 0:return Response({"mobile": sms_status["msg"]}, status=status.HTTP_400_BAD_REQUEST)else:code_record = VerifyCode(code=code, mobile=mobile)code_record.save()return Response({"mobile": mobile}, status=status.HTTP_201_CREATED)

云片网单条短信发送的使用说明:

(5)配置url

from users.views import SmsCodeViewset# 配置codes的url
router.register(r'code', SmsCodeViewset, base_name="code")

 开始验证

输入不合法的手机号

输入合法的手机号

会返回输入的手机号码,并受到短信验证码

7.6.user serializer 和validator验证

完成注册的接口

用户注册需要填写手机号,验证码和密码,相当于create model操作,所以继承CreateModelMixin

(1)修改UserProfile中mobile字段

mobile = models.CharField("电话",max_length=11,null=True, blank=True)

设置允许为空,因为前端只有一个值,是username,所以mobile可以为空

(2)users/serializers.py

代码里面我都写好了注释,就不再重复解释了

class UserRegSerializer(serializers.ModelSerializer):'''用户注册'''#UserProfile中没有code字段,这里需要自定义一个code序列化字段code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4,error_messages={"blank": "请输入验证码","required": "请输入验证码","max_length": "验证码格式错误","min_length": "验证码格式错误"},help_text="验证码")#验证用户名是否存在username = serializers.CharField(label="用户名", help_text="用户名", required=True, allow_blank=False,validators=[UniqueValidator(queryset=User.objects.all(), message="用户已经存在")])#验证codedef validate_code(self, code):# 用户注册,已post方式提交注册信息,post的数据都保存在initial_data里面#username就是用户注册的手机号,验证码按添加时间倒序排序,为了后面验证过期,错误等verify_records = VerifyCode.objects.filter(mobile=self.initial_data["username"]).order_by("-add_time")if verify_records:# 最近的一个验证码last_record = verify_records[0]# 有效期为五分钟。five_mintes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)if five_mintes_ago > last_record.add_time:raise serializers.ValidationError("验证码过期")if last_record.code != code:raise serializers.ValidationError("验证码错误")else:raise serializers.ValidationError("验证码错误")# 所有字段。attrs是字段验证合法之后返回的总的dictdef validate(self, attrs):#前端没有传mobile值到后端,这里添加进来attrs["mobile"] = attrs["username"]#code是自己添加得,数据库中并没有这个字段,验证完就删除掉del attrs["code"]return attrsclass Meta:model = Userfields = ('username','code','mobile')

(3)users/views.py

class UserViewset(CreateModelMixin,viewsets.GenericViewSet):'''用户'''serializer_class = UserRegSerializer

(4)配置url

router.register(r'users', UserViewset, base_name="users")

测试代码:

  • 输入已经存在的用户名
  • 不输入验证码

7.7.django信号量实现用户密码修改

(1)完善用户注册

添加一条用户短信验证码数据之后进行验证。

user/views.py

class UserViewset(CreateModelMixin,viewsets.GenericViewSet):'''用户'''serializer_class = UserRegSerializerqueryset = User.objects.all()

user/serializer.py添加

 fields = ('username','code','mobile','password')

(2)password不能明文显示和加密保存

需要重载Create方法

 #输入密码的时候不显示明文password = serializers.CharField(style={'input_type': 'password'},label=True,write_only=True)#密码加密保存def create(self, validated_data):user = super(UserRegSerializer, self).create(validated_data=validated_data)user.set_password(validated_data["password"])user.save()return user

这是重载Create方法,下面介绍如何用信号量来实现

信号量

(1)users下面创建signals.py

# users/signals.pyfrom django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Tokenfrom django.contrib.auth import get_user_model
User = get_user_model()# post_save:接收信号的方式
#sender: 接收信号的model
@receiver(post_save, sender=User)
def create_user(sender, instance=None, created=False, **kwargs):# 是否新建,因为update的时候也会进行post_saveif created:password = instance.password#instance相当于user
        instance.set_password(password)instance.save()

(2)还需要重载配置

users/apps.py

# users/apps.pyfrom django.apps import AppConfigclass UsersConfig(AppConfig):name = 'users'verbose_name = "用户管理"def ready(self):import users.signals

AppConfig自定义的函数,会在django启动时被运行

现在添加用户的时候,密码就会自动加密存储了

7.8.vue和注册功能联调

生成token的两个重要步骤,一是payload,二是encode

users/views.py

class UserViewset(CreateModelMixin,viewsets.GenericViewSet):'''用户'''serializer_class = UserRegSerializerqueryset = User.objects.all()def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)user = self.perform_create(serializer)re_dict = serializer.datapayload = jwt_payload_handler(user)re_dict["token"] = jwt_encode_handler(payload)re_dict["name"] = user.name if user.name else user.usernameheaders = self.get_success_headers(serializer.data)return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)def perform_create(self, serializer):return serializer.save()

接口写好后,接下来测试

输入合法的手机号,会发送验证码到手机上,然后输入验证码和密码,登录成功

转载于:https://www.cnblogs.com/derek1184405959/p/8813641.html

Django REST framework+Vue 打造生鲜超市(六)相关推荐

  1. Django REST framework+Vue 打造生鲜超市(四)

    目录 生鲜超市(一)    生鲜超市(二)    生鲜超市(三) 生鲜超市(四)    生鲜超市(五)    生鲜超市(六) 生鲜超市(七)    生鲜超市(八)    生鲜超市(九) 生鲜超市(十) ...

  2. Django REST framework+Vue 打造生鲜超市(十)

    目录 生鲜超市(一)    生鲜超市(二)    生鲜超市(三) 生鲜超市(四)    生鲜超市(五)    生鲜超市(六) 生鲜超市(七)    生鲜超市(八)    生鲜超市(九) 生鲜超市(十) ...

  3. Django REST framework+Vue 打造生鲜超市(三)

    代码下载 github 教程 学习自慕课网-前端vue结合后端DjangoFramework的在线生鲜超市 四.xadmin后台管理 4.1.xadmin添加富文本插件 (1)xadmin/plugi ...

  4. Django REST framework+Vue 打造生鲜超市(二)

    代码下载 github 教程 学习自慕课网-前端vue结合后端DjangoFramework的在线生鲜超市 三.Models设计 3.1.项目初始化 (1)进虚拟环境下安装 django2.0.2 d ...

  5. Django REST framework+Vue 打造生鲜超市(十三)

    目录 生鲜超市(一)    生鲜超市(二)    生鲜超市(三) 生鲜超市(四)    生鲜超市(五)    生鲜超市(六) 生鲜超市(七)    生鲜超市(八)    生鲜超市(九) 生鲜超市(十) ...

  6. Django REST framework+Vue 打造生鲜超市(五)

    六.商品类别数据展示 6.1. 商品类别数据接口 (1)商品分类有两个接口: 一种是全部分类:一级二级三级 一种是某一类的分类以及商品详细信息: 开始写商品分类的接口 (2)序列化 给分类添加三级分类 ...

  7. Django进阶 Django REST framework+Vue 打造生鲜超市第一天 搭建环境

    新人学习django 是按照这个大佬的教程学习的 链接: https://www.cnblogs.com/derek1184405959/p/8733194.html. 很多步骤都是按照上面的教程学习 ...

  8. Django REST framework+Vue 打造生鲜电商项目(笔记八)

    (form:http://www.cnblogs.com/derek1184405959/p/8862569.html) 十一.pycharm 远程代码调试 第三方登录和支付,都需要有服务器才行(回调 ...

  9. python全栈生鲜电商_Django REST framework+Vue 打造生鲜电商项目(笔记十)

    (from:https://www.cnblogs.com/derek1184405959/p/8877643.html  有修改) 十三.首页.商品数量.缓存和限速功能开发 首先把pycharm环境 ...

最新文章

  1. JDK8中好用的日期处理-LocalDate类-LocalTime-LocalDateTIme,mysql解决时区相差13小时的问题,日期格式器DateTimeFormatter
  2. CoreOS Linux Alpha的重大漏洞已修复
  3. STM32移植RT-Thread的串口只能接收一个字节数据的问题
  4. 对家庭网络设备行业的理解
  5. wxWidgets:wxChoicebook类用法
  6. 最佳实践丨三种典型场景下的云上虚拟IDC(私有池)选购指南
  7. jscript换行等特殊字符
  8. Linux工作笔记-使用find和grep检索文件或子文件中是否包含指定字符串
  9. 我是如何从双非本科到拿到微软校招offer的?
  10. 详解Go语言的计时器
  11. UVA 11367 Full Tank? 最短路
  12. 看动画轻松理解「链表」实现「 LRU 缓存淘汰算法」
  13. Qt安装教程(Qt 6.4)
  14. 你靠谱吗?看看“价值观”究竟有多重要
  15. BSC链节点搭建 保姆级详细教程
  16. .html怎么查看源代码,html的网页源代码怎么查看
  17. 如火般的风马: 快速迁移本地项目到Bluemix云平台
  18. PPT文档中如何插入超链接
  19. 制作名片设计需要哪些要素
  20. django Using the URLconf defined in test02.urls, Django tried these URL patterns, in this order:

热门文章

  1. .NET项目发布网站具体步骤和注意事项
  2. 视图之二--视图中数据的更新
  3. 使用jsonp进行跨域访问
  4. OpenStack Heat服务介绍 (三)
  5. hive的静态分区与动态分区-用法实例
  6. 三种复方门冬维甘滴眼液的抗菌能力比较
  7. NFL discussion调研
  8. 搭建Hexo最后一步:hexo d时 没反应 直接跳过解决办法(转)
  9. 机器学习(二十二)——推荐算法中的常用排序算法, Tri-training
  10. 【机器学习】传统目标检测算法之HOG