一:用户部分:

用户注册:

用户注册序列化器:

 import re

 from django_redis import get_redis_connection
from rest_framework import serializers from users.models import User 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)
token = serializers.CharField(label='JWT Token', read_only=True) class Meta:
model = User
fields = ('id', 'username', 'password', 'mobile', 'password2', 'sms_code', 'allow', 'token') 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_username(self, value):
"""用户名不能是纯数字"""
if re.match(r'^\d+$', value):
raise serializers.ValidationError('用户名不能都是数字') return value def validate_mobile(self, value):
"""手机号格式,手机号是否已注册"""
# 手机号格式
if not re.match(r'^1[3-9]\d{9}$', value):
raise serializers.ValidationError('手机号格式不正确') # 手机号是否已注册
count = User.objects.filter(mobile=value).count()
if count > 0:
raise serializers.ValidationError('手机号已存在') return value def validate_allow(self, value):
"""是否同意协议"""
if value != 'true':
raise serializers.ValidationError('请同意协议')
return value def validate(self, attrs):
"""两次密码是否一致,短信验证码是否正确"""
# 两次密码是否一致
password = attrs['password']
password2 = attrs['password2'] if password != password2:
raise serializers.ValidationError('两次密码不一致') # 短信验证码是否正确
# 获取真实的短信验证码内容
mobile = attrs['mobile']
redis_conn = get_redis_connection('verify_codes')
real_sms_code = redis_conn.get('sms_%s' % mobile) # bytes if not real_sms_code:
raise serializers.ValidationError('短信验证码已过期') # 对比
sms_code = attrs['sms_code'] # str
real_sms_code = real_sms_code.decode() # str
if sms_code != real_sms_code:
raise serializers.ValidationError('短信验证码错误') return attrs def create(self, validated_data):
"""保存注册用户信息"""
# 清除无用的数据
del validated_data['password2']
del validated_data['sms_code']
del validated_data['allow'] # # 调用父类create方法
# user = super().create(validated_data)
#
# # 对密码进行加密
# password = validated_data['password']
# user.set_password(password)
# user.save() # 调用create_user方法
user = User.objects.create_user(**validated_data) # 注册成功就让用户处于登录状态
# 由服务器签发一个jwt token,保存用户身份信息
from rest_framework_jwt.settings import api_settings jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER # 生成载荷信息(payload)
payload = jwt_payload_handler(user)
# 生成jwt token
token = jwt_encode_handler(payload) # 给user对象增加一个属性token,保存jwt token信息
user.token = token # 返回user
return user
对应视图函数:
 from django.shortcuts import render
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView, CreateAPIView from users.models import User
from users.serializers import CreateUserSerializer
# Create your views here. # POST /users/
# class UserView(GenericAPIView):
class UserView(CreateAPIView):
serializer_class = CreateUserSerializer # def post(self, request):
# """
# 注册用户信息的保存:
# 1. 获取参数并进行校验(参数完整性,两次密码是否一致,手机号格式,手机号是否已注册,短信验证码是否正确,是否同意协议)
# 2. 保存注册用户信息
# 3. 返回应答,注册成功
# """
# # 1. 获取参数并进行校验(参数完整性,两次密码是否一致,手机号格式,手机号是否已注册,短信验证码是否正确,是否同意协议)
# serializer = self.get_serializer(data=request.data)
# serializer.is_valid(raise_exception=True)
#
# # 2. 保存注册用户信息(create)
# serializer.save()
#
# # 3. 返回应答,注册成功
# return Response(serializer.data, status=status.HTTP_201_CREATED) # url(r'^usernames/(?P<username>\w{5,20})/count/$', views.UsernameCountView.as_view()),
class UsernameCountView(APIView):
"""
用户名数量
"""
def get(self, request, username):
"""
获取指定用户名数量
"""
count = User.objects.filter(username=username).count() data = {
'username': username,
'count': count
} return Response(data) # url(r'^mobiles/(?P<mobile>1[3-9]\d{9})/count/$', views.MobileCountView.as_view()),
class MobileCountView(APIView):
"""
手机号数量
"""
def get(self, request, mobile):
"""
获取指定手机号数量
"""
count = User.objects.filter(mobile=mobile).count() data = {
'mobile': mobile,
'count': count
} return Response(data)

用到的知识点:

##### 2. JWT token

1)session认证

```python
1. 接收用户名和密码
2. 判断用户名和密码是否正确
3. 保存用户的登录状态(session)
session['user_id'] = 1
session['username'] = 'smart'
session['mobile'] = ''
4. 返回应答,登录成功
``` session认证的一些问题: > 1. session存储在服务器端,如果登录的用户过多,服务器开销比较大。
> 2. session依赖于cookie,session的标识存在cookie中,可能会有CSRF(跨站请求伪造)。 2)jwt 认证机制(替代session认证) ```
1. 接收用户名和密码
2. 判断用户名和密码是否正确
3. 生成(签发)一个jwt token(token中保存用户的身份信息) 公安局(服务器)=>签发身份证(jwt token)
4. 返回应答,将jwt token信息返回给客户端。
``` 如果之后需要进行身份认证,客户端需要将jwt token发送给服务器,由服务器验证jwt token的有效性。 3)jwt 的数据格式 ```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik
pvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFO
``` a)headers头部 ```
{
"token类型声明",
"加密算法"
}
``` base64加密(很容易被解密) b)payload(载荷):用来保存有效信息 ```
{
"user_id": 1,
"username": "smart",
"mobile": "",
"exp": "有效时间"
}
``` base64加密 c)signature(签名):防止jwt token被伪造 将headers和payload进行拼接,用.隔开,使用一个密钥(secret key)进行加密,加密之后的内容就是签名。 jwt token是由服务器生成,密钥保存在服务器端。 ##### 3. jwt 扩展签发jwt token
from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)

 

最新文章

  1. 在网页中嵌入地图API
  2. SSM框架——使用MyBatis Generator自动创建代码
  3. rails命令避免直接操作数据库
  4. Django admin site(一)ModelAdmin Options
  5. oracle_11g 不同用户之间的数据迁移
  6. thinkPHP add、save无法添加、修改不起作用
  7. WS_CLIPCHILDREN和WS_CLIPSIBLINGS的理解(转载)
  8. heartbeat单独提供高可用服务
  9. vue-cli 去掉严格模式:
  10. python3中time模块与datetime模块的简单用法
  11. py-day4-1 python reduce函数
  12. hibernate(*.hbm.xml)中新添加的字段被标记为红色(找不到)的解决方法
  13. windows php7 安装redis扩展
  14. Appium1.9.1 之 Desired Capabilities 释疑
  15. ubuntu分辨率
  16. tomcat7简单优化
  17. eclipse 开发 spring 、 springboot项目调试时一直跳转到 SilentExitExceptionHandler.exitCurrentThread 方法
  18. OpenCV教程(42) xml/yaml文件的读写
  19. HDU 4714 Treecycle(树形dp)
  20. 个人知识管理系统Version1.0开发记录(07)

热门文章

  1. ckeditor使用教程
  2. 【深度学习笔记】Anaconda及开发环境搭建
  3. bzoj 4530 [Bjoi2014]大融合——LCT维护子树信息
  4. Unit04: JavaScript 概述 、 JavaScript 基础语法 、 流程控制
  5. Asp.net中的web.config配置文件(转)
  6. &quot;废物利用&quot;也抄袭——废旧喷墨打印机和光驱DIY&quot;绘图仪&quot;
  7. https 请求的端口是443 注意
  8. 杂项:Hadoop
  9. Vim编辑器基本操作学习(一)
  10. 002:MySQL升级以及访问连接