一、定义用户模型类
1、Django默认用户认证系统
django.contrib.auth包含认证框架的核心和默认的模型,django.contrib.contenttypes
是Django内容类型系统,它允许权限与你创建的模型关联。
2、Django默认用户模型类
Django认证系统用户模型类位置 django.contrib.auth.models.User 。一般情况下需要继承父类AbstractUser ,User对象必选属性有【username、password
】,可选属性有【email、first_name、last_name、last_login、date_joined、is_active 、is_staff、is_superuse
】,判断用户是否通过认证【is_authenticated
】。设置密码:set_password(raw_password),
校验密码:check_password(raw_password)
。
3、自定义用户模型类:
在使用命令时如果app的名字是user会出现包冲突,建议包名改成users。然后再models.py中粘贴代码。只要使用了models就需要在dev文件的INSTALLED_APPS注册一下。
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
"""自定义用户模型类"""
mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号') #unique指定唯一值
class Meta:
db_table = 'tb_users' #指定表的名字
verbose_name = '用户' #设置模型在admin站点显示的中文名
verbose_name_plural = verbose_name
def __str__(self):
return self.username
还需要在dev文件中加入配置
AUTH_USER_MODEL = '应用名.模型类名'
AUTH_USER_MODEL = 'auth.User' #User是模型的名字
4、在urls中加入路由
# 用户名是否注册
re_path(r'usernames/(?P<username>\w{5,20})/count/', views.UsernameCountView.as_view()),
二、短信验证码
1、业务过程
-
生成和发送短信验证码
-
保存短信验证码
-
redis pipeline的使用
-
检查是否在60s内有发送记录
2、后端实现
短信验证码需要企业才可以发送,我们只是为了实现相应的功能逻辑。
redis配置我在前面已经说过,使用这里就直接使用,只需要在之前的dev配置redis代码中加入。
"verify_codes": { # 存储验证码
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/2", #如果redis在虚拟机中记得修改
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
生成和发送短信验证码、保存短信验证码、redis pipeline的使用、检查60秒内是否发送。在views.py文件写入代码。短信验证的实现主要是在写入redis数据库时写入两条数据,一个是send_flag_手机号当做发过短信的标记和加上60秒的过期时间,另一个是sms_手机号:验证码,设置过期时间。
from django_redis import get_redis_connection
from random import randint
import logging
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .constants import *
logger = logging.getLogger('django')
class SMSCodeView(APIView):
"""短信验证码"""
def get(self, request, mobile):
"""
@param mobile: 手机号
"""
# 创建redis连接对象
redis_conn = get_redis_connection('verify_codes') # verify_codes 是配置里面的CACHES字段
# 先从redis获取发送的标记
send_flag = redis_conn.get('send_flag_%s' % mobile)
# 如果取到了标记,说明此手机号频繁发短信
if send_flag:
return Response({'message': '手机频繁发送短信'}, status=status.HTTP_400_BAD_REQUEST)
# 生成验证码
sms_code = '%06d' % randint(0, 999999)
logger.info(sms_code)
# 创建redis管道:(把多次redis操作装入管道中,将来一次性去执行,减少redis的连接操作)
pl = redis_conn.pipeline()
# 把验证码存储到redis数据库
# redis_conn.setex('sms_%s' % mobile, SMS_CODE_REDIS_EXPIRES, sms_code)
pl.setex('sms_%s' % mobile, SMS_CODE_REDIS_EXPIRES, sms_code)
# 存储一个标记,表示手机号已发送过短信 标记有效期60s
# redis_conn.setex('send_flag_%s' % mobile, SEND_SMS_CODE_INTERVAL, 1)
pl.setex('send_flag_%s' % mobile, SEND_SMS_CODE_INTERVAL, 1)
# 执行管道
pl.execute()
# 响应
return Response({'message': 'ok'})
3、在urls加上路由
re_path是一个带有正则path
# 手机号是否注册
re_path(r'mobiles/(?P<mobile>1[3-9]\d{9})/count/', views.MobileCountView.as_view()),
三、解决跨域问题
因为代码是前后端分离的,所以我们需要为后端添加跨域访问的支持。
参考文档https://github.com/ottoyiu/django-cors-headers/
1、安装
pip install django-cors-headers
2、dev中配置修改
添加应用
INSTALLED_APPS = (
...
'corsheaders',
...
)
中间层设置
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
...
]
添加白名单 (任意位置),凡是出现在白名单中的域名,都可以访问后端接口,CORS_ALLOW_CREDENTIALS 指明在跨域访问中,后端是否支持对cookie的操作。
# CORS
CORS_ORIGIN_WHITELIST = (
'127.0.0.1:8080',
'localhost:8080',
)
CORS_ALLOW_CREDENTIALS = True # 允许携带cookie
四、用户注册
后端对于前端返回的数据大部分都需要校验。
1、创建serializers.py文件,创建序列化器检验数据
使用rest_framework包中的serializers。在创建视图类的时候视图类需要继承serializers.ModelSerializer,使用ModelSerializer是因为我们验证的是数据库的中数据字段
class CreateUserSerializer(serializers.ModelSerializer):
"""
创建用户序列化器
"""
password2 = serializers.CharField(label='确认密码', write_only=True)
sms_code = serializers.CharField(label='短信验证码', write_only=True)
allow = serializers.CharField(label='同意协议', write_only=True)
class Meta:
model = User
fields = ('id', 'username', 'password', 'password2', 'sms_code', 'mobile', 'allow')
extra_kwargs = {
'username': {
'min_length': 5,
'max_length': 20,
'error_messages': {
'min_length': '仅允许5-20个字符的用户名',
'max_length': '仅允许5-20个字符的用户名',
}
},
'password': {
'write_only': True,
'min_length': 8,
'max_length': 20,
'error_messages': {
'min_length': '仅允许8-20个字符的密码',
'max_length': '仅允许8-20个字符的密码',
}
}
}
def validate_mobile(self, value):
"""验证手机号"""
if not re.match(r'^1[3-9]\d{9}$', value):
raise serializers.ValidationError('手机号格式错误')
return value
def validate_allow(self, value):
"""检验用户是否同意协议"""
if value != 'true':
raise serializers.ValidationError('请同意用户协议')
return value
def validate(self, data):
# 判断两次密码
if data['password'] != data['password2']:
raise serializers.ValidationError('两次密码不一致')
# 判断短信验证码
redis_conn = get_redis_connection('verify_codes')
mobile = data['mobile']
real_sms_code = redis_conn.get('sms_%s' % mobile)
if real_sms_code is None:
raise serializers.ValidationError('无效的短信验证码')
if data['sms_code'] != real_sms_code.decode():
raise serializers.ValidationError('短信验证码错误')
return data
def create(self, validated_data):
"""
创建用户
"""
# 移除数据库模型类中不存在的属性
del validated_data['password2']
del validated_data['sms_code']
del validated_data['allow']
user = super().create(validated_data)
# 调用django的认证系统加密密码
user.set_password(validated_data['password'])
user.save()
return user
2、在urls中加上路由
# 注册用户
path('users/', views.UserView.as_view()),
3、常见知识点
read_only:只用于序列化输出使用 write_only:只用于但序列化输入时使用 super():将方法重写之后重新调用父类的该方法
如果继承了ModelSerializer,就需要在Meta类中指明模型 ,fields是选出我们需要检验的字段,extra_kwargs可以对一些字段加上约束条件,也可以在创建序列化器是直接校验。
class Meta:
model = User # 从User模型中映射出序列化字段
fields = ['id', 'username', 'password', 'password2', 'mobile', 'sms_code', 'allow', 'token']
extra_kwargs = { # 修改字段选项
'username': {
'min_length': 5,
'max_length': 20,
'error_messages': { # 自定义校验出错后的错误信息提示
'min_length': '用户名长度不小于5',
'max_length': '用户名长度不大于20',
}
}
}