JWT 认证 以及Django 中的应用

jwt 认证

私钥、公钥、CA认证

用一套加密规则 加密和解密

RSA加密 (非对称的加密)

摘要算法:MD5 FTP/互联网下载软件校验MD5

私钥 --RSA算法-->公钥

RSA原理

加密解密:只要你有我的公钥你就能知道我发的消息是什么。

数字签名:只要用我的公钥把一个消息解密了,那么这个消息就一定是我发的。

小故事:公钥、私钥、CA认证阅读

组成:

  • 村长博客: www.cnblogs.com/leguan1314

  • header.payload.sign ==>> 头部.载荷.签名

  • 依赖包:

    • import hmac
      import time
      import json
      import base64
      import hashlib
      import jwt

头部:

  • 就是一个 字典 包含了 typ: token 类型 alg: 签名算法
headers = {
    # 申明token类型 `type`
    "typ": "JWT",
    # 声明你的签名算法
    "alg": "HS256"
}

# 头部被 `base64` 编码
header_string = base64.urlsafe_b64encode(json.dumps(headers).encode("utf-8")).replace(b'=', b'')
# 载荷(用户信息)

载荷:

  • 用户信息
payload = {
    # TODO 公传参数
    # 签发者
    "iss": "liuzhichao",
    # 什么时候给的会话凭证
    "iat": int(time.time()),
    # 过期时间(什么时候过期)
    "exp": int(time.time()) + 100,
    # 接收 `jwt` 的一方
    "aud": "luffy",
    # TODO 自定义参数
    # 用户名
    "username": "XXX",
    # 用户ID
    "user_id": "101"
}

# 载荷被 `base64` 编码
payload_string = base64.urlsafe_b64encode(json.dumps(payload).encode("utf-8")).replace(b'=', b'')

签名:

  • 一个 加密的字符串
# 签名
# 用于加密的 字符串
secret = "+&0p1d$l$lq%xm0qvet0i++!p-*e1ql*5t!kajgjm$fe_ycf1n"

sign_data = "{}.{}".format(header_string.decode("utf-8"), payload_string.decode("utf-8")).encode("utf-8")

sign = base64.urlsafe_b64encode(hmac.new(secret.encode("utf-8"),sign_data,hashlib.sha256).digest())

将三部分用点拼接 生成

print("{}.{}.{}".format(
    header_string.decode("utf-8"),
    payload_string.decode("utf-8"),
    sign.decode("utf-8"),
))

效验 jwt:

from rest_framework import authentication


class JwtAuthentication(authentication.BaseAuthentication):

    def authenticate(self, request):
        jwt = request.META.get("HTTP_AUTHORIZATION")

        # 校验 `jwt` 是否合法
        # 获取到 `token`
        jwt = jwt.encode("utf-8")

        # 分割 `jwt`
        header_payload_string, sign_string = jwt.rsplit(b'.', 1)
        header_string, payload_string = header_payload_string.split(b'.', 1)

        header_data = base64.urlsafe_b64decode(header_string)
        # 获取到头部数据
        header = json.loads(header_data.decode("utf-8"))
        # 获取到载荷数据
        payload = base64.urlsafe_b64decode(payload_string)
        # 获取到签名
        signature = base64.urlsafe_b64decode(sign_string)

        # 获取到签名算法
        alg = header.get('alg')

        if not alg:
            print("没有算法")
            raise ValueError("alg is not null")

        secret = "+&0p1d$l$lq%xm0qvet0i++!p-*e1ql*5t!kajgjm$fe_ycf1n".encode("utf-8")

        if not hmac.compare_digest(
                signature, hmac.new(secret, header_payload_string, hashlib.sha256).digest()
        ):
            print("验证失败")
            raise ValueError("验证签名失败")

        print("验证通过")
        payload_dic = json.loads(payload.decode("utf-8"))
        print(payload_dic)

        # 过期时间校验
        if not payload_dic.get("exp") > int(time.time()):
            raise ValueError("jwt过期了")

        from django.contrib.auth.models import User

        return User.objects.get(pk=payload_dic.get("user_id")), None

直接用模块 生成 jwt:

# 用模块生成
# 秘钥
secret = "+&0p1d$l$lq%xm0qvet0i++!p-*e1ql*5t!kajgjm$fe_ycf1n"

expire_time = int(time.time() + 1)  # 1 小时后超时
# 生成 gwt
encoded = jwt.encode(
    #  header                              密钥					编码方式
    {'id': 4294967296, 'exp': expire_time}, secret.encode("utf8"), algorithm='HS256')
	
encoded_str = str(encoded, encoding='utf-8')
print(encoded_str)

time.sleep(2)
# 解码
info = jwt.decode(encoded_str, secret, algorithm='HS256')
print(info)

也可以 使用 django 自带的 jwt

  • pip install djangorestframework-jwt

其他点:

  • 注册 rest_framework app 设置 ALLOWED_HOSTS = ["*"] 为所有

  • 在 serializer 序列化器 中 的 validata(self, data) 函数中 获取 request 对象

    并在对象中 获取 请求头 也就是 jwt 的 字符串

    def validata(self, data):
        # 获取 request  对象
        request = self.context.get('request')
        # 获取请求头 也就是  jwt
        jwt = request.META.get('HTTP_AUTHORIZATION')
        
        
    
posted @ 2019-04-22 13:08  拐弯  阅读(610)  评论(0编辑  收藏  举报