欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JSON Web Token令牌(JWT)的使用(二)重写自带的用户认证和token流程

程序员文章站 2024-03-20 20:04:46
...

前文,查看官方文档:https://yiyibooks.cn/xx/Django_1.11.6/topics/auth/index.html

token应用流程:

  • 初次登录:用户初次登录,输入用户名密码
  • 密码验证:服务器从数据库取出用户名和密码进行验证
  • 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT
  • 返还JWT:服务器的HTTP RESPONSE中将JWT返还
  • 带JWT的请求:以后客户端发起请求,HTTP REQUEST HEADER中的Authorizatio字段都要有值,为JWT,注意JWT后带一个空格

内置的认证登陆

在进行用户登陆验证的时候,如果是自己写代码,就必须要先查询数据库,看用户输入的用户名是否存在于数据库中;
如果用户存在于数据库中,然后再验证用户输入的密码,这样一来就要自己编写大量的代码。

事实上,Django已经提供了内置的用户认证功能。

为何要自己写认证

有时候我们需要用到邮箱或者手机登录而不只是用户名,所以需要自己重写功能,在utils文件夹里创建一个文件authenticate.py里面写:

# 在当前文件里面,定义的是自定义的认证系统
from django.contrib.auth.backends import ModelBackend
import re
from users.models import Users
import logging
# 这是日志
log = logging.getLogger('users')


class UserPhoneEmailAuthBackend(ModelBackend):
    # 当前的类是用来做自定义的认证用户
    def authenticate(self, request, username=None, password=None, **kwargs):
        '''重写父类的方法
        :param request: 请求
        :param username: 可能是手机或者email
        :param password: 密码
        :param kwargs: 其他参数,键值形式
        :return: user模型对象
        '''
        # 1.不论是用户名还是手机还是邮箱先获取到user对象
        try:
            if re.match(r'^1[3456789][\d]{9}$', username):
                user = Users.objects.get(phone=username)
            elif re.match(r'^[\w_]{3,15}@[\w]{2,11}.com$', username):
                user = Users.objects.get(email=username)
            else:
                user = Users.objects.get(username=username)
        except Users.DoseNotExist:
            user = None
            log.error('auth验证失败 ', username)
        # 拿到user后进行校验
        if user is not None and user.check_password(password):
            return user

如何使用的jwt自带的验证视图

直接在对应的urls.py里配置即可

from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
	# 登录验证
    url(r'^login/$', obtain_jwt_token),]

在前端登录ajax请求

通过ajax请求发送用户名和密码。验证成功后会得到token。
然后把token存到localStorage,这个是固定存储网页关闭了也存在,在设置.py里可以设置过期时间。

$('#login').click(function () {
        // 用户名,密码
        var username = $('#username').val();
        var userpwd = $('#userpwd').val();

        var send_data = {
            'username': username,
            'password': userpwd
        };
        send_data = JSON.stringify(send_data);
        // 发送请求
        $.ajax({
            url:'http://127.0.0.1:8000/users/login/',
            type:'POST',
            data:send_data,
            dataType:'json',
            contentType:'application/json',
            success:function (rec_data) {
                // 返回的数据username, userid, token
                console.log(rec_data)
                // 先清空本地的再进行存储
                localStorage.clear(); 
                localStorage.token = rec_data['token'];
                // 获取到本地的token
                console.log('本地的token', localStorage.token)
            },
            fail:function () {
                alert('登录失败')
            }
        })
    })

重写jwt的返回内容

因为默认使用的返回只有token,我们需要更多地内容比如username和id,当然也可以前端解析base64来实现,这里使用后端重写来返回更多内容。
还是在utils文件夹里的authenticate.py写一个函数:

def my_jwt_response(token, user=None, request=None):
    '''
    jwt登录验证成功后,自定义的jwt登录返回数据
    :param token: 
    :param user: user对象
    :param request:
    :return: 返回json类型数据
    '''
    return {
        'token': token,
        'username': user.username,
        'user_id': user.id
    }

然后在自己的设置文件里配置,我的是dev.py,添加这个配置路径也就是第二个键值对

# 设置过期时间和jwt返回值
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=60*60*24),
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'shanghuishop.utils.authenticate.my_jwt_response'
}

这时候前端访问即可得到:

Object {user_id: 21, token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1N…ExIn0.6IEeAsMgg_qRCivw0ErmLqvYmlvVF7ckvpxjNmdfUGs", username: "1111"}

JWT如何返回用户信息或者修改信息

serializers.py写一个序列化器

fields里面填需要的值就行,我在models添加了一些值,便于修改

class UserLoginSerClass(serializers.ModelSerializer):
    '''
    方便
    '''
    class Meta:
        model = Users
        fields = ('id', 'username', 'email', 'phone', 'truename', 'gender', 'qq_num')

view.py设置指定模型(重要)

这个导的是RetrieveUpdateAPIView,可以实现get和put请求

from rest_framework.generics import *
class LoginUserInfoView(RetrieveUpdateAPIView):
    serializer_class = UserLoginSerClass

    # 指定单个模型
    def get_object(self):
        # print('展示单个模型', self.request.user)
        return self.request.user

js根据JWT的值发送get请求获取信息

这是用户信息界面,get请求需要添加请求头设置:

  • ‘Authorization’: 'JWT ’ + token

来访问,如果有效就能取到用户信息,并且设置了当前页面的标签值

$.ajax({
        url: 'http://127.0.0.1:8000/users/userinfo/',
        method: 'GET',
        headers: {
            'Authorization': 'JWT ' + token
        },
		// 成功时调用
        success:function (data) {
            console.log(data);
            // 设置显示的对应内容
            $('#username').val(data['username']);
            $('#phone').val(data['phone']);
            $('#email').val(data['email'])
        },
        error:function (err_data) {
            console.log(err_data);
            alert('未登录,请跳转到登录页面');
            // 如果提示是401则是JWT过期跳转登录页面
            if (err_data['status'] == 401){
                location.href = 'http://127.0.0.1:8080/login.html'
            }
        }
    })

js里根据JWT的值发送PUT请求

其实和GET是一样的,要注意添加请求头即可

$('#change_personal_data').click(function () {
        // 修改按钮,使可以输入
        $('#truename').attr('disabled', false).css('border', 'solid 1px red');
        // $('#gender').attr('disabled', false).css('border', 'solid 1px red');
        $('#gender').css('display', 'none');
        $('.add_sex').css('display', 'block');
        $('#qq_number').attr('disabled', false).css('border', 'solid 1px red');
    });
    
$('#change_confirm').click(function () {
        // 确认修改
        var username = $('#username').val();
        var phone = $('#phone').val();
        var email = $('#email').val();
        var truename = $('#truename').val();
        var qq_num = $('#qq_number').val();
        var gender = $("input[name='sex']:checked").val();

        if (gender==0){
            gender = 'male'
        }else if(gender==1){
            gender = 'female'
        }
        var send_data = {
            'username': username,
            'phone': phone,
            'email': email,
            'truename': truename,
            'qq_num': qq_num,
            'gender': gender
        };
        send_data = JSON.stringify(send_data);
        console.log(send_data);
        // 发送修改用户信息请求
        $.ajax({
            url: 'http://127.0.0.1:8000/users/userinfo/',
            type: 'PUT',
            headers:{
                'Authorization': 'JWT ' + token
            },
            data: send_data,
            dataType:'json',
            contentType:'application/json',
            success: function (data) {
                console.log(data);
                $('#truename').attr('disabled', true).css('border', 'solid 0px red');
                // $('#gender').attr('disabled', false).css('border', 'solid 1px red');
                $('#gender').css('display', 'block').text(data['gender']);
                $('.add_sex').css('display', 'none');
                $('#qq_number').attr('disabled', true).css('border', 'solid 0px red');
            },
            error:function (data) {
                alert('failed');
                console.log(data)
            }
        })
    })
相关标签: JWT