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


官方文档: 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提供内置的用户认证功能。

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

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

为何要自己写认证

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

#当前文件夹里面,定义的是自定义的认证系统
from django.contrib.auth.backends import ModelBackend
import re
from user import models

'''Django自带的认证系统
    
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
            user = UserModel._default_manager.get_by_natural_key(username)
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (#20760).
            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user'''

'''当前的类,是用来定义的认证方法'''
class UserPhoneEmailAuthBackend(ModelBackend):


    def authenticate(self, request, username=None, password=None, **kwargs):

        '''

        :param request:
        :param username:可能是手机号码/邮箱/用户名
        :param password:
        :param kwargs:
        :return:
        '''

        #1. todo 不管是用户或者邮箱或者手机号码,第一件事获取对象
        try:
            #todo 先通过正则,判断出手机号码/用户名/邮箱
            if re.match(r'^1[\d]{10}$',username):
                user = models.User.objects.get(phone=username)
                print('111111111111111111eeeeeeeeerrrrrrrrrrrrrrrrr')
            elif re.match('^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$',username):
                user = models.User.objects.get(email=username)
            else:
                user = models.User.objects.get(username=username)

        except models.User.DoesNotExist:
            user = None


            # todo 拿到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里可以设置过期时间。

$(function () {
    $('#llogin').click(function () {
        //获取用户名和密码
        //用户名
        var username = $('#lusername').val();
        var password = $('#lpassword').val();

        //拼接json数据向后端传递数据
        var data = {
            'username':username,
            'password':password
        };
        //将对象转成json数据
        data_json = JSON.stringify(data)
        //发送

        $.ajax({
            url:'http://127.0.0.1:8000/user/login/',
            type:'POST',
            data:data_json,
            contentType:'application/json',
            dataType:'json',
            success:function (data) {
                alert(data)
                console.log(data);
                //清空token
                localStorage.clear();
                //储存token
                localStorage.token=data['token'];
                //返回到前端

                console.log( '返回到前端');
                console.log( localStorage.token)

            },
            error:function (data){
                alert('请求失败')
            }

        })
    })
});

重写jwt的返回内容

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

def jwt_response_username_userid_token(token,user=None,request=None):
    '''

    JWT登入验证成功之后 ,自定义处理返回数据
    :param token:
    :param user:
    :param request:
    :return:
    '''

    data = {
        'token':token,
        'username':user.username,
        'user_id':user.id
    }
    return data

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

# 设置过期时间和jwt返回值
JWT_AUTH = {
        #jwt过期时间
        #'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=60),
        'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
        #配置自定义jwt返回内容
        'JWT_RESPONSE_PAYLOAD_HANDLER':'shanghui.utils.utils.jwt_response_username_userid_token'
}

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

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

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

serializers.py写一个序列化器

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

class LodinUserInfoSerializer(serializers.ModelSerializer):
    ''''email
    为了偷懒直接用
    '''
    class Meta:
        model = models.User
        fields = ('id','username','phone','email')

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

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

class LodinUserInfoView( RetrieveAPIView):
    '''用户信息返回给前端'''

    # 1.指定序列化器
    serializer_class = serializers.LodinUserInfoSerializer
    # todo 进行权限的指定
    #两种都可以
    permission_classes = (IsAuthenticated,)
    #permission_classes = [IsAuthenticated]

    # 2.指定单个模型
    def get_object(self):
        print('=================================')
        print(self.request.user)
        return self.request.user

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

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

  • ‘Authorization’: 'JWT ’ + token
    来访问,如果有效就能取到用户信息,并且设置了当前页面的标签值
$(function () {
    token = localStorage.token
    // alert(token)
    //get()等价于ajax({})

    $.ajax({
        url:'http://127.0.0.1:8000/user/userinfo/',
        method:'GET',
        headers:{
            //‘JWT ’里面必须带空格
            'Authorization':'JWT '+ token
        },
        success:function (data) {
            // alert('ok');
            console.log(data);

            console.log( '返回到前端');
            console.log( localStorage.token);
            //替换用户名
            email = data['email'];
            username = data['username'];
            phone = data['phone'];
            console.log(email,phone,username);
            $('#uusername').html(username);
            $('#uusername1').val(username);
            $('#uemail').val(email);
            $('#uphone').val( phone)

        },
        error:function (data) {
            console.log(data);
            console.log('error');
            console.log(data['status']);
            if (data['status']==401){
                location.href = 'http://127.0.0.1:8080/templates/login.html'
            }
            // alert('失败');
        }

    });

   
});

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

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

$('#btn').click(function () {

         $.ajax({
        url:'http://127.0.0.1:8000/user/email/',

        headers:{
            //‘JWT ’里面必须带空格
            'Authorization':'JWT '+ token
        },
             type:'PUT',
             id:'',
             //email:'1246081324@qq.com',
             data:{
                _method:'PUT',
                 "email":'1246081324@qq.com'
             },
             dataType:'json',
        success:function (data) {
            alert('ok');
            console.log(data);


            console.log( '返回到前端');
            console.log( localStorage.token);
            替换用户名
            email = data['email'];
            username = data['username'];
            phone = data['phone'];
            console.log(email,phone,username);
            $('#uusername').html(username);
            $('#uusername1').val(username);
            $('#uemail').val(email);
            $('#uphone').val( phone)

        },
        error:function (data) {
            console.log(data);
            console.log('error');
            console.log(data['status']);
            if (data['status']==401){
                location.href = 'http://127.0.0.1:8080/templates/login.html'
            }
            // alert('失败');

        $.ajax({
        url:'http://127.0.0.1:8000/user/email/',
        method:'PUT',
        headers:{
            //‘JWT ’里面必须带空格
            'Authorization':'JWT '+ token
        },
        success:function (data) {
            // alert('ok');
            console.log(data);

            console.log( '返回到前端');
            console.log( localStorage.token);
            替换用户名
            email = data['email'];
            username = data['username'];
            phone = data['phone'];
            console.log(email,phone,username);
            $('#uusername').html(username);
            $('#uusername1').val(username);
            $('#uemail').val(email);
            $('#uphone').val( phone)

        },
        error:function (data) {
            console.log(data);
            console.log('error');
            console.log(data['status']);
            if (data['status']==401){
                location.href = 'http://127.0.0.1:8080/templates/login.html'
            }
            // alert('失败');


        }

    })
    });
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值