zoukankan      html  css  js  c++  java
  • drf_jwt

    JWT:

    1、组成: header.payload.signature 头.载荷.签名 2、示例: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Im93ZW4iLCJleHAiOjE1NTgzMDM1NDR9.4j5QypLwufjpqoScwUB9LYiuhYcTw1y4dPrvnv7DUyo 3:介绍: header:一般存放如何处理token的方式:加密的算法、是否有签名等 payload:数据的主体部分:用户信息、发行者、过期时间等 signature:签名:将header、payload再结合密码盐整体处理一下
    工作原理:
    
    1) jwt = base64(头部).base64(载荷).hash256(base64(头部).base(载荷).密钥)
    2) base64是可逆的算法、hash256是不可逆的算法
    3) 密钥是固定的字符串,保存在服务器
    官网:https://github.com/jpadilla/django-rest-framework-jwt
    
    安装:pip install djangorestframework-jwt

    使用:一般是搭配xadmin去实现后台管理

    获得token:

    在user/url.py里:
    
    
    from django.urls import path
    from rest_framework_jwt.views import obtain_jwt_token
    urlpatterns = [
        path('login/', obtain_jwt_token),
    ]
    
    
    利用postman测试发射post请求:
    
    
    接口:http://127.0.0.1:8000/user/login/
    
    数据:
    {
        "username":"admin",
        "password":"admin"
    }
    可能存在一些问题:
    
    Unable to log in with provided credentials
    
    
    原因是这种算法内部是需要使用auth_user表去获取用户的账号和密码数据的,而我们没有创建相关的数据,因此需要创建一些数据:
    
     python manage.py createsuperuser

    再次尝试:得到token值:
     "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXh
    wIjoxNTY5MjAyODc1LCJlbWFpbCI6IjEzMDYzNDczMzgwQDE2My5jb20ifQ.JgbSItmx0sa4JHuA5I4J58gcoeCgTLKZaPj0T-f5OwI"


    虽说拿到了后端生成的token值,可怎么让其真正的实现认证功能呢:

     在settinngs.py里配置jwt的相关数据
    
    import datetime
    JWT_AUTH = {
        # 过期时间
        'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
        # 自定义认证类
        'JWT_RESPONSE_PAYLOAD_HANDLER': 'user.utils.jwt_response_payload_handler',  
    }
     序列化组件 user/serializers.py
    
    from rest_framework import serializers
    from .models import User
    class UserModelSerializer(serializers.ModelSerializer):
        """轮播图序列化器"""
        class Meta:
            model = User
            fields = ["username", "mobile"]
    
    
    需要注意的是:User这张表继承的是  from django.contrib.auth.models import AbstractUser  ,因为jwt内部走的是auth_user这张表。    同时还需要在配置里将 AUTH_USER_MODEL = 'app的名字.User' 添加上,表示重写了auth的认证表
    同时:因为重写了auth表,需要删除一些迁移记录文件:django/contrib/admin/migrations
    django/contrib/auth/migrations
    xadmin/migrations  如果使用xadmin作为后台管理使用
    reversion/migrations 同上
    user/migrations
    在user/models.py下:
    
    
    from django.db import models
    
    # Create your models here.
    from django.contrib.auth.models import AbstractUser
    
    class  User(AbstractUser):
        mobile = models.CharField(max_length=32,default=0)
        age = models.IntegerField(default=0)
    自定义response的返回结果: user/utils.py
    
    from .serializers import UserModelSerializers
    def jwt_response_payload_handler(token, user=None, request=None):
        return {
            'token': token,
            # 拿到的是一个序列化后的对象,多个对象加上many=True
            'user': UserModelSerializer(user).data
        }
        # restful 规范
        # return {
        #     'status': 0,
        #     'msg': 'OK',
        #     'data': {
        #         'token': token,
        #         'username': user.username
        #     }
        # }

    上述操作完成了jwt的自定义返回值,现在需要实现的是jwt全局认证,基于drf的认证组件实现

    import jwt
    from rest_framework.exceptions import AuthenticationFailed
    from rest_framework_jwt.authentication import jwt_decode_handler
    from rest_framework_jwt.authentication import get_authorization_header
    from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
    
    
    class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
        def authenticate(self, request):
            # 下面的 token获取,可以直接 request.META.get()去获取
            token = get_authorization_header(request)
            # 可以在此处 对请求头的字段做出一些限制,实现反扒
            if not token:
                raise AuthenticationFailed('Authorization字段是必须的')
    
            try:
                payload = jwt_decode_handler(token)
            except jwt.ExpiredSignature:
                raise AuthenticationFailed('签名过期')
            except jwt.DecodeError:
                raise AuthenticationFailed('错误的解码签名')
            except jwt.InvalidTokenError:
                raise AuthenticationFailed('非法用户')
    
            user = self.authenticate_credentials(payload)
    
            return (user, token)

    当然了,需要在settings.py里完成相关配置:全局启用

    EST_FRAMEWORK = {
        # 认证模块
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'user.authentications.JSONWebTokenAuthentication',
        ),
    }
    需要知道,drf_jwt是基于drf框架实现的
    局部启用禁用:任何一个cbv类首行
    
    
    # 局部禁用
    authentication_classes = []
    
    # 局部启用
    from user.authentications import JSONWebTokenAuthentication
    authentication_classes = [JSONWebTokenAuthentication]

    上述操作时针对于用户密码而言的,如果是多方式登陆如何利用jwt实现呢?

    from django.contrib.auth.backends import ModelBackend
    from .models import User
    import re
    class JWTModelBackend(ModelBackend):
        def authenticate(self, request, username=None, password=None, **kwargs):
            """
            :param request:
            :param username: 前台传入的用户名,可以是多方式下的数据
            :param password: 前台传入的密码
            :param kwargs:
            :return:
            """
            try:
                if re.match(r'^1[3-9]d{9}$', username):
                    user = User.objects.get(mobile=username)
                elif re.match(r'.*@.*', username):
                    user = User.objects.get(email=username)
                else:
                    user = User.objects.get(username=username)
            except User.DoesNotExist:
                return None  # 认证失败就返回None即可,jwt就无法删除token
            # 用户存在,密码校验通过,是活着的用户 is_active字段为1
            if user and user.check_password(password) and self.user_can_authenticate(user):
                return user  # 认证通过返回用户,交给jwt生成token
    配置多方式登陆:   settings.py
    
    AUTHENTICATION_BACKENDS = ['user.utils.JWTModelBackend']

    手动签发jwt: 拥有原生登陆基于model类user对象签发 jwt

    from rest_framework_jwt.settings import api_settings

    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)


    # 了解,原生视图
    # 原生APIView可以实现手动签发 jwt
    class LoginAPIView(APIView):
    def post(self):
    # 完成手动签发
    pass

  • 相关阅读:
    cscope使用技巧
    GNU的strong symbol和weak symbol
    vim自定义插件放入pathogen管理
    kernel生成针对x86架构的tags和cscope数据库
    vim+cscope简易教程
    mac重装系统
    Mac升级bash到最新版本
    Mac中提升权限修改系统目录
    macbook中gcc替换为gnu gcc
    固定二进制位的整型变量
  • 原文地址:https://www.cnblogs.com/changwenjun-666/p/11574245.html
Copyright © 2011-2022 走看看