使用jwt登录认证有一个明显的好处就是不用再服务器端保存token,它只是在服务器端生成token和验证token,减轻了服务器端数据库的压力,而且较比传统的session认证也安全一些!
使用步骤:
一 在项目的settings中进行配置
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}
二 创建用户模型类 (该模型类继承自AbstractUser)
class User(AbstractUser):
mobile = models.CharField(max_length=11,unique=True,verbose_name='手机号码')
class Meta:
db_table = 'user'
verbose_name = '用户信息表'
verbose_name_plural = verbose_name
三 编写用户注册views 视图函数
from django.shortcuts import render
# Create your views here.
from rest_framework.generics import CreateAPIView
from rest_framework.views import APIView
from . import ser
class Register(CreateAPIView):
serializer_class = ser.CreateUserSer
四 编写用户注册的序列化器
注:password2 在模型类User中不存在,序列化时因填写参数write_only=True,不然会报错!
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from .models import User
class CreateUserSer(serializers.ModelSerializer):
mobile = serializers.CharField(max_length=11,min_length=11,label='手机号')
password2 = serializers.CharField(max_length=12,min_length=8,write_only=True,label='重置密码')
def validate(self, attrs):
password = attrs['password']
password2 = attrs['password2']
if password2 != password:
raise serializers.ValidationError('两次密码不一致,请重新输入!')
return attrs
def validate_mobile(self,value):
import re
if re.match(r'1[3-9]/d{9}',value):
raise serializers.ValidationError('手机号格式不对,请重新输入!')
return value
def create(self, validated_data):
del validated_data['password2']
user = super().create(validated_data)
user.set_password(validated_data['password'])
user.save()
# 补充生成记录登录状态的token
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)
user.token = token
return user
class Meta:
model = User
fields = ('id','password','password2','mobile','username')
五 总路由urls
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^users/', include('users.urls')),
]
六 用户模块下的分路由
from django.conf.urls import include, url
from rest_framework_jwt.views import obtain_jwt_token
from . import views
urlpatterns = [
url(r'authorizations/', obtain_jwt_token, name='authorizations'),
url(r'register/$', views.Register.as_view()),
]
注:obtain_jwt_token 由jwt提供的登录视图
七.在用户模块下 新增utils模块
from django.contrib.auth.backends import ModelBackend
def jwt_response_payload_handler(token, user=None, request=None):
"""
自定义jwt认证成功返回数据,因为jwt默然只返回token,现自定义jwt认证成功后返回参数
"""
return {
'token': token,
'user_id': user.id,
'username': user.username
}
def get_user_by_account(accout):
"""
(增加手机或用户名直接登录功能)
"""
import re
from .models import User
try:
if re.match(r'1[3-9]\d{9}$',accout):
user = User.objects.get(mobile=accout)
else:
user = User.objects.get(username= accout)
except User.DoesNotExist:
return None
else:
return user
class UsernameMobileAuthBackend(ModelBackend):
"""
自定义用户登录认证
"""
def authenticate(request, username=None, password=None, **kwargs):
user = get_user_by_account(username)
if user is not None and user.check_password(password):
return user
八 修改配置文件 settings
# 自定义用户模型类
AUTH_USER_MODEL = 'users.User'
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),# token过期时间设置
'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',
# 自定义的jwt认证成功后的返回数据
}
# 在配置文件中告知Django使用我们自定义的认证后端
AUTHENTICATION_BACKENDS = [
'users.utils.UsernameMobileAuthBackend',
]
九 数据库迁移,测试!
用户注册测试
用户登录测试