zoukankan      html  css  js  c++  java
  • 5 分钟,快速入门 Python JWT 接口认证

    1. 前言

    大家好,我是安果!

    为了反爬或限流节流,后端编写接口时,大部分 API 都会进行权限认证,只有认证通过,即:数据正常及未过期才会返回数据,否则直接报错

    本篇文章以 Django 为例,聊聊后端 JWT 接口认证的操作流程

    2. JWT 介绍

    JWT 全称为 JSON Web Token,是目前主流的跨域认证解决方案

    数据结构由 3 部分组成,中间由「 **. **」分割开

    它们分别是:

    • Header 头部

    • Payload 负载

    • Signature 签名

    # JWT 数据的格式
    # 组成方式:头部.负载.签名
    Header.Payload.Signature
    

    其中

    Header 用于设置签名算法及令牌类型,默认签名算法为 「 HS256 」,令牌类型可以设置为「 JWT 」

    Payload 用于设置需要传递的数据,包含:iss 签发人、exp 过期时间、iat 签发时间等

    Signature 用于对 Header 和 Payload 进行签名,默认使用的签名算法为 Header 中指定的算法

    # JWT 数据组成
    # Header. Payload. Signature
    # Header:{ "alg": "HS256","typ": "JWT"}
    # Payload:iss、exp、iat等
    ​# Signature:签名
    Signature = HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret)
    

    PS:base64UrlEncode 相比 Base64 算法,会将结果中的「 = 」省略、「 + 」替换成「 - 」、「 / 」替换成「 _ 」

    3. 实战一下

    首先,在虚拟环境中安装 JWT 依赖包

    # 安装jwt依赖包
    pip3 install pyjwt
    

    然后,定义一个方法用于生成 JWT Token

    需要注意的是,生成 JWT Token 时需要指定过期时间、加密方式等

    import time
    import jwt
    from django.conf import settings
    
    def generate_jwt_token(user):
        """
        生成一个JWT Token
        :param user:
        :return:
        """
        # 设置token的过期时间戳
        # 比如:设置7天过期
        timestamp = int(time.time()) + 60 * 60 * 24 * 7
    
        # 加密生成Token
        # 加密方式:HS256
        return jwt.encode({"userid": user.pk, "exp": timestamp}, settings.SECRET_KEY,'HS256')
    

    接着,编写一个认证类

    该类继承于「 BaseAuthentication 」基类,重写内部函数「 authenticate() 」,对请求参数进行 JWT 解密,并进行数据库查询,只有认证通过才返回数据,否则抛出异常

    import time
    
    import jwt
    from django.conf import settings
    from django.contrib.auth import get_user_model
    from rest_framework import exceptions
    from rest_framework.authentication import BaseAuthentication, get_authorization_header
    
    User = get_user_model()
    
    class JWTAuthentication(BaseAuthentication):
        """自定义认证类"""
    
        keyword = 'jwt'
        model = None
    
        def get_model(self):
            if self.model is not None:
                return self.model
            from rest_framework.authtoken.models import Token
            return Token
    
        """
        A custom token model may be used, but must have the following properties.
    ​
        * key -- The string identifying the token
        * user -- The user to which the token belongs
        """
    
        def authenticate(self, request):
            auth = get_authorization_header(request).split()
    
            if not auth or auth[0].lower() != self.keyword.lower().encode():
                return None
    
            if len(auth) !=2:
                raise exceptions.AuthenticationFailed("认证异常!")
    
            # jwt解码
            try:
                jwt_token = auth[1]
                jwt_info = jwt.decode(jwt_token, settings.SECRET_KEY,'HS256')
    
                # 获取userid
                userid = jwt_info.get("userid")
    
                # 查询用户是否存在
                try:
                    user = User.objects.get(pk=userid)
                    return user, jwt_token
                except Exception:
                    raise exceptions.AuthenticationFailed("用户不存在")
            except jwt.ExpiredSignatureError:
                raise exceptions.AuthenticationFailed("抱歉,该token已过期!")
    

    最后,在视图集 ViewSet 中,只需要在属性「 authentication_classes 」中指定认证列表即可

    from rest_framework import viewsets
    from .models import *
    from .serializers import *
    from .authentications import *
    
    class GoodsViewSet(viewsets.ModelViewSet):
        # 所有商品数据
        queryset = Goods.objects.all()
    
        # 序列化
        serializer_class = GoodsSerializer
    
        # JWT授权
        authentication_classes = [JWTAuthentication]
    

    4. 最后

    在实际项目中,一般在登录的时候生成 JWT Token,后续接口中只需要在请求头中设置 JWT Token 即可正常返回数据

    import requests
    
    url = "***.***.****"
    
    payload={}
    headers = {
      'AUTHORIZATION': 'jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiJVTmJCRTJTRlNndm5DU0c3amdQZGJVIiwiZXhwIjoxNjI2MDk5NDA5fQ.cxXsRulEWWQotNpb7XwlZbISrrpb7rSRCjkLsyb8WDM'
    }
    
    response = requests.request("GET", url, headers=headers, data=payload)
    print(response.text)
    

    如果你觉得文章还不错,请大家 点赞、分享、留言 下,因为这将是我持续输出更多优质文章的最强动力!

    分享 Python 自动化及爬虫、数据分析实战干货,欢迎关注。
  • 相关阅读:
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    block的是发送信号的线程,又不是处理槽函数的线程
  • 原文地址:https://www.cnblogs.com/xingag/p/15109103.html
Copyright © 2011-2022 走看看