INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication', # 全局设置
],
]
执行数据库迁移: python manage.py makemigrations
、python manage.py migrate
urls.py增加:
from rest_framework.authtoken import views
urlpatterns = [
# drf 自带的认证
path(r'api-token-auth/', views.obtain_auth_token),
]
pip install djangorestframework-jwt
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
...
],
]
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
# jwt自带的token认证模式
path(r'api-token-auth/', obtain_jwt_token),
]
settings.py增加
AUTHENTICATION_BACKENDS = (
'common.auth.CustomBackend',
)
common/auth.py增加:
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q
User = get_user_model()
class CustomBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = User.objects.get(Q(username=username) | Q(mobile=username))
if user.check_password(password):
return user
except Exception as e:
return None
utils.sms.py
class Sms:
def __init__(self, api_key=''):
self.api_key = api_key
self.single_send_url = "#"
def send_sms(self, code, mobile):
return {'code': 0, 'msg': '发送成功'}
serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.conf import settings
from .models import VerifyCode
import datetime
import re
User = get_user_model()
class SmsSerializer(serializers.Serializer):
mobile = serializers.CharField(max_length=11)
def validate_mobile(self, mobile):
"""
验证手机号
:param data:
:return:
"""
# 验证手机号格式
if not re.match(settings.REGEX_MOBILE, mobile):
raise serializers.ValidationError('手机号码非法')
# 校验是否已经存在
if User.objects.filter(mobile=mobile).count():
raise serializers.ValidationError('用户已经存在')
# 验证发送频率
one_mintes_ago = datetime.datetime.now() - datetime.timedelta(hours=0, minutes=1, seconds=0)
if VerifyCode.objects.filter(add_time__gt=one_mintes_ago, mobile=mobile).count():
raise serializers.ValidationError('距离上一次发送未超过1分钟')
return mobile
views.py
import random
from rest_framework.mixins import CreateModelMixin
from rest_framework import viewsets, status
from rest_framework.response import Response
from utils.sms import Sms
from .serializers import SmsSerializer
from .models import VerifyCode
class SmsCodeViewSet(CreateModelMixin, viewsets.GenericViewSet):
serializer_class = SmsSerializer
def generate_code(self):
seeds = "1234567890"
random_str = []
for i in range(6):
random_str.append(random.choice(seeds))
return ''.join(random_str)
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
# validated_data 经过验证的数据
mobile = serializer.validated_data['mobile']
code = self.generate_code()
smsapi = Sms()
sms_status = smsapi.send_sms(code, 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,
'code': code,
}, status=status.HTTP_201_CREATED)
urls.py
router.register(r'codes', SmsCodeViewset, base_name="codes")
serializers.py
from rest_framework.validators import UniqueValidator
class UserRegSerializer(serializers.ModelSerializer):
code = serializers.CharField(label='验证码', required=True, write_only=True, min_length=4, max_length=4,
error_messages={
'blank': '请输入验证码',
'required': '请输入验证码',
'max_length': '验证码格式错误',
'min_length': '验证码格式错误',
})
username = serializers.CharField(label='用户名', help_text='用户名', required=True, allow_blank=False,
validators=[UniqueValidator(queryset=User.objects.all(), message='用户已经存在')])
password = serializers.CharField(label='密码', help_text='密码', write_only=True, style={'input_type': 'password'})
def validate_code(self, code):
verify_row = VerifyCode.objects.filter(mobile=self.initial_data['username']).order_by('-add_time')
if verify_row:
last_row = verify_row[0]
mintes_ago = datetime.datetime.now() - datetime.timedelta(hours=0, minutes=5, seconds=0)
if last_row.add_time < mintes_ago:
raise serializers.ValidationError('验证码过期')
if code != last_row.code:
raise serializers.ValidationError('验证码不正确')
else:
raise serializers.ValidationError('验证码错误')
return code
# 处理字段为model所需
def validate(self, attrs): # validata后所有的字段
attrs['mobile'] = attrs['username']
del attrs['code']
return attrs
class Meta:
model = User
fields = ('username', 'code', 'password')
# 处理密码加密 方式一
def create(self, validated_data):
user = super(UserRegSerializer, self).create(validated_data=validated_data)
user.set_password(validated_data['password'])
user.save()
return user
views.py
from rest_framework.mixins import CreateModelMixin
from rest_framework import viewsets
class UserViewSet(CreateModelMixin, viewsets.GenericViewSet):
serializer_class = UserRegSerializer
signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model
User = get_user_model()
@receiver(post_save, sender=User)
def create_user(sender, instance=None, created=False, **kwargs):
if created:
password = instance.password
instance.set_password(password)
instance.save()
apps.py
class UsersConfig(AppConfig):
...
def ready(self):
import users.signals
views.py
class UserViewSet(CreateModelMixin, viewsets.GenericViewSet):
serializer_class = UserRegSerializer
queryset = User.objects.all()
def perform_create(self, serializer):
"""重写,返回对象"""
return serializer.save()
def create(self, request, *args, **kwargs):
""重写, 生成jwt,并返回""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = self.perform_create(serializer)
re_dict = serializer.data
# 生成jwt
payload = jwt_payload_handler(user)
re_dict['token'] = jwt_encode_handler(payload)
re_dict['name'] = user.name if user.name else user.username
headers = self.get_success_headers(serializer.data)
return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)