jwt用户登陆认证

使用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',
]

九  数据库迁移,测试!

用户注册测试

 

用户登陆测试