一:用户部分:
用户注册:
用户注册序列化器:
1 import re 2 3 from django_redis import get_redis_connection 4 from rest_framework import serializers 5 6 from users.models import User 7 8 9 class CreateUserSerializer(serializers.ModelSerializer): 10 """创建用户序列化器类""" 11 password2 = serializers.CharField(label='重复密码', write_only=True) 12 sms_code = serializers.CharField(label='短信验证码', write_only=True) 13 allow = serializers.CharField(label='是否同意协议', write_only=True) 14 token = serializers.CharField(label='JWT Token', read_only=True) 15 16 class Meta: 17 model = User 18 fields = ('id', 'username', 'password', 'mobile', 'password2', 'sms_code', 'allow', 'token') 19 20 extra_kwargs = { 21 'username': { 22 'min_length': 5, 23 'max_length': 20, 24 'error_messages': { 25 'min_length': '仅允许5-20个字符的用户名', 26 'max_length': '仅允许5-20个字符的用户名', 27 } 28 }, 29 'password': { 30 'write_only': True, 31 'min_length': 8, 32 'max_length': 20, 33 'error_messages': { 34 'min_length': '仅允许8-20个字符的密码', 35 'max_length': '仅允许8-20个字符的密码', 36 } 37 } 38 } 39 40 # (参数完整性,手机号格式,手机号是否已注册,是否同意协议,两次密码是否一致,短信验证码是否正确) 41 def validate_username(self, value): 42 """用户名不能是纯数字""" 43 if re.match(r'^\d+$', value): 44 raise serializers.ValidationError('用户名不能都是数字') 45 46 return value 47 48 def validate_mobile(self, value): 49 """手机号格式,手机号是否已注册""" 50 # 手机号格式 51 if not re.match(r'^1[3-9]\d{9}$', value): 52 raise serializers.ValidationError('手机号格式不正确') 53 54 # 手机号是否已注册 55 count = User.objects.filter(mobile=value).count() 56 if count > 0: 57 raise serializers.ValidationError('手机号已存在') 58 59 return value 60 61 def validate_allow(self, value): 62 """是否同意协议""" 63 if value != 'true': 64 raise serializers.ValidationError('请同意协议') 65 return value 66 67 def validate(self, attrs): 68 """两次密码是否一致,短信验证码是否正确""" 69 # 两次密码是否一致 70 password = attrs['password'] 71 password2 = attrs['password2'] 72 73 if password != password2: 74 raise serializers.ValidationError('两次密码不一致') 75 76 # 短信验证码是否正确 77 # 获取真实的短信验证码内容 78 mobile = attrs['mobile'] 79 redis_conn = get_redis_connection('verify_codes') 80 real_sms_code = redis_conn.get('sms_%s' % mobile) # bytes 81 82 if not real_sms_code: 83 raise serializers.ValidationError('短信验证码已过期') 84 85 # 对比 86 sms_code = attrs['sms_code'] # str 87 real_sms_code = real_sms_code.decode() # str 88 if sms_code != real_sms_code: 89 raise serializers.ValidationError('短信验证码错误') 90 91 return attrs 92 93 def create(self, validated_data): 94 """保存注册用户信息""" 95 # 清除无用的数据 96 del validated_data['password2'] 97 del validated_data['sms_code'] 98 del validated_data['allow'] 99 100 # # 调用父类create方法 101 # user = super().create(validated_data) 102 # 103 # # 对密码进行加密 104 # password = validated_data['password'] 105 # user.set_password(password) 106 # user.save() 107 108 # 调用create_user方法 109 user = User.objects.create_user(**validated_data) 110 111 # 注册成功就让用户处于登录状态 112 # 由服务器签发一个jwt token,保存用户身份信息 113 from rest_framework_jwt.settings import api_settings 114 115 jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER 116 jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER 117 118 # 生成载荷信息(payload) 119 payload = jwt_payload_handler(user) 120 # 生成jwt token 121 token = jwt_encode_handler(payload) 122 123 # 给user对象增加一个属性token,保存jwt token信息 124 user.token = token 125 126 # 返回user 127 return user
对应视图函数:
1 from django.shortcuts import render 2 from rest_framework import status 3 from rest_framework.response import Response 4 from rest_framework.views import APIView 5 from rest_framework.generics import GenericAPIView, CreateAPIView 6 7 from users.models import User 8 from users.serializers import CreateUserSerializer 9 # Create your views here. 10 11 12 # POST /users/ 13 # class UserView(GenericAPIView): 14 class UserView(CreateAPIView): 15 serializer_class = CreateUserSerializer 16 17 # def post(self, request): 18 # """ 19 # 注册用户信息的保存: 20 # 1. 获取参数并进行校验(参数完整性,两次密码是否一致,手机号格式,手机号是否已注册,短信验证码是否正确,是否同意协议) 21 # 2. 保存注册用户信息 22 # 3. 返回应答,注册成功 23 # """ 24 # # 1. 获取参数并进行校验(参数完整性,两次密码是否一致,手机号格式,手机号是否已注册,短信验证码是否正确,是否同意协议) 25 # serializer = self.get_serializer(data=request.data) 26 # serializer.is_valid(raise_exception=True) 27 # 28 # # 2. 保存注册用户信息(create) 29 # serializer.save() 30 # 31 # # 3. 返回应答,注册成功 32 # return Response(serializer.data, status=status.HTTP_201_CREATED) 33 34 35 # url(r'^usernames/(?P<username>\w{5,20})/count/$', views.UsernameCountView.as_view()), 36 class UsernameCountView(APIView): 37 """ 38 用户名数量 39 """ 40 def get(self, request, username): 41 """ 42 获取指定用户名数量 43 """ 44 count = User.objects.filter(username=username).count() 45 46 data = { 47 'username': username, 48 'count': count 49 } 50 51 return Response(data) 52 53 54 # url(r'^mobiles/(?P<mobile>1[3-9]\d{9})/count/$', views.MobileCountView.as_view()), 55 class MobileCountView(APIView): 56 """ 57 手机号数量 58 """ 59 def get(self, request, mobile): 60 """ 61 获取指定手机号数量 62 """ 63 count = User.objects.filter(mobile=mobile).count() 64 65 data = { 66 'mobile': mobile, 67 'count': count 68 } 69 70 return Response(data)
用到的知识点:
##### 2. JWT token 1)session认证 ```python 1. 接收用户名和密码 2. 判断用户名和密码是否正确 3. 保存用户的登录状态(session) session['user_id'] = 1 session['username'] = 'smart' session['mobile'] = '13155667788' 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": "13155667788", "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)
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:用django框架开发一个B2C购物网站用户注册知识点总结2 - Python技术站