使用jwt登陆认证有一个明显的好处就是不用再服务器端保存token,它只是在服务器端生成token和验证token,减轻了服务器端数据库的压力,并且较比传统的session认证也安全一些!python
使用步骤:数据库
一 在项目的settings中进行配置django
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 视图函数api
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 session
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', ]
九 数据库迁移,测试!
用户注册测试
用户登陆测试