使用itsdangerous生成确认令牌

首先我们来看生成令牌和解码令牌的代码:

from itsdangerous import TimedJSONWebSignatureSerializer

    s = TimedJSONWebSignatureSerializer(app.config['SECRET_KEY'], expires_in=3600)

    token = s.dumps({'confirm': 23})

    data = s.loads(token)

根据我的理解,Serializer构造了它的实例s,它的第一个参数是我们设置的config变量,也就是密钥。

然后实例调用dumps函数, 用密钥对数据进行了加密, 生成令牌字符串token。

最后s调用loads函数,用密钥对令牌进行解码, 得到data字典。

那么这个过程中到底发生了什么?

******************************************************************************************************

一:我们首先来看TimedJSONWebSignatureSerializer类的构造函数:

*********************************************************************************************************

class TimedJSONWebSignatureSerializer(JSONWebSignatureSerializer):
    DEFAULT_EXPIRES_IN = 3600

    def __init__(self, secret_key, expires_in=None, **kwargs):
        JSONWebSignatureSerializer.__init__(self, secret_key, **kwargs)
        if expires_in is None:
            expires_in = self.DEFAULT_EXPIRES_IN
        self.expires_in = expires_in

    我们可以看到TimedJSONWebSignatureSerializer继承了JSONWebSignatureSerializer类。

        (1)在构造函数中调用了父类的构造函数。我们传入的参数是:

            secret_key=app.config['SECRET_KEY']

        (2)然后设置了实例的expires_in属性 = 3600.

二:下面我们来看JSONWebSignatureSerializer的构造函数:

class JSONWebSignatureSerializer(Serializer):
    jws_algorithms = {
        'HS256': HMACAlgorithm(hashlib.sha256),
        'HS384': HMACAlgorithm(hashlib.sha384),
        'HS512': HMACAlgorithm(hashlib.sha512),
        'none': NoneAlgorithm(),
    }
    default_algorithm = 'HS256'

    default_serializer = compact_json
    def __init__(self, secret_key, salt=None, serializer=None,
                 signer=None, signer_kwargs=None, algorithm_name=None):
        Serializer.__init__(self, secret_key, salt, serializer,
                            signer, signer_kwargs)
        if algorithm_name is None:
            algorithm_name = self.default_algorithm
        self.algorithm_name = algorithm_name
        self.algorithm = self.make_algorithm(algorithm_name)

    JSONWebSignatureSerializer继承了Serializer类

        (1)在构造函数中调用了父类的构造函数,参数除了secret_key,其他的都默认是None。

        (2)因为algorithm_name=None, 所以设置了实例属性

            self.algrithm_name = 'HS256'

        (3)然后设置了属性

            self.algorithm = self.make_algorithm(algorithm_name) 参数就是‘HS256’

           1.make_algorithm函数:

    def make_algorithm(self, algorithm_name):
        try:
            return self.jws_algorithms[algorithm_name]
        except KeyError:
            raise NotImplementedError('Algorithm not supported')

          2.self.jws_algorithms是JSONWebSignatureSerializer的类变量,是一个字典(上文可见):

              查字典我们可知,make_algorithm函数返回的是HMACAlgorithm(hashlib.sha256)


          所以实例属性self.algorithm = HMACAlgorithm(hashlib.sha256)


总结一下:JSONWebSignatureSerializer的构造函数做了两件事

    1.调用父类Serializer的构造函数Serializer.__init__(self, secret_key, salt, serializer, signer, signer_kwargs)

    2.设置实例属性self.algorithm_name = ‘HS256’; 设置实例属性self.algorithm = HMACAlgorithm(hashlib.sha256)

三:下面我们来看Serializer的构造函数:

class Serializer(object):
    default_serializer = json
    default_signer = Signer
    def __init__(self, secret_key, salt=b'itsdangerous', serializer=None,
                 signer=None, signer_kwargs=None):
        self.secret_key = want_bytes(secret_key)
        self.salt = want_bytes(salt)
        if serializer is None:
            serializer = self.default_serializer
        self.serializer = serializer
        self.is_text_serializer = is_text_serializer(serializer)
        if signer is None:
            signer = self.default_signer
        self.signer = signer
        self.signer_kwargs = signer_kwargs or {}
    (1)首先设置实例属性self.secret_key = wantbytes(secret_key)

         (* wantbytes函数的作用是判断参数字符串是不是unicode类型, 如果是把它编码成utf-8,, 就是把u''字符串编码成b'')

    (2)然后设置实例属性self.salt = wantbytes(b'itsdangerous')

    (3)然后设置实例属性self.serializer = json

    (4)然后设置实例属性self.is_text_serializer = is_text_serializer(serializer)

        1. is_text_serializer函数:

   

def is_text_serializer(serializer):
    """Checks wheather a serializer generates text or binary."""
    return isinstance(serializer.dumps({}), text_type)

         text_type = unicode

         可以知道这个函数是检查serializer.dumps({})生成的是不是unicode字符串;如果是:self.is_text_serializer = true;


         self.is_text_serializer = flase


    (5)然后设置属性self.signer = Signer

    (6)然后设置属性self.signer_kwargs = {}



总结一下, 当我们调用 s = Serializer(app.config['SECRET_KEY'], expires_in=3600)的时候创建了实例s 并为这个实例设置了一系列的属性, 请留意这些实例属性,下文我们会用到。


*****************************************************************************************************************************************************************

 二:然后我们来看 token = s.dumps({'confirm': 23})

******************************************************************************************************************************************************************

dumps函数:

    def dumps(self, obj, salt=None, header_fields=None):
        """Like :meth:`~Serializer.dumps` but creates a JSON Web Signature.  It
        also allows for specifying additional fields to be included in the JWS
        Header.
        """
        header = self.make_header(header_fields)
        signer = self.make_signer(salt, self.algorithm)
        return signer.sign(self.dump_payload(header, obj))

(1)header = self.make_header(header_fields)

 make_header函数:

    def make_header(self, header_fields):
        header = JSONWebSignatureSerializer.make_header(self, header_fields)
        iat = self.now()
        exp = iat + self.expires_in
        header['iat'] = iat
        header['exp'] = exp
        return header

    1. header = JSONWebSignatureSerializer.make_header(self, header_fields)

    def make_header(self, header_fields):
        header = header_fields.copy() if header_fields else {}
        header['alg'] = self.algorithm_name
        return header
        结果是header = {'alg': ‘HS256’}

    2.iat = self.now()

        now()函数返回当前的时间戳

    3.exp=当前时间加上期待时间, exp就是过期的时间


总结一下, 最后make_header函数返回的是字典{‘alg’: 'HS256', 'iat': 当前时间, 'exp': 过期时间}

header = self.make_header(header_fields) = {‘alg’: 'HS256', 'iat': 当前时间, 'exp': 过期时间}


(2)signer = self.make_signer(salt, self.algorithm) = self.make_signer(None, HMACAlgorithm(hashlib.sha256)))

     make_signer函数:

    def make_signer(self, salt=None, algorithm=None):
        if salt is None:
            salt = self.salt
        key_derivation = 'none' if salt is None else None
        if algorithm is None:
            algorithm = self.algorithm
        return self.signer(self.secret_key, salt=salt, sep='.',
            key_derivation=key_derivation, algorithm=algorithm)

    实例属性self.salt = wantbytes(b'itsdangerous')

    所以函数最后返回的是,

          return self.singer(app.config['SECRET_KEY'], salt=b'itsdangerous',  sep='.', key_derivation=None, algorithm=HMACAlgorithm(hashlib.sha256))

    实例属性self.signer = Signer (类), 所以函数最后返回的是

          return Singer(app.config['SECRET_KEY'], salt=b'itsdangerous',  sep='.', key_derivation=None, algorithm=HMACAlgorithm(hashlib.sha256))

Singer是一个类, 其构造函数如下:

class Signer(object):
    default_digest_method = staticmethod(hashlib.sha1)
    default_key_derivation = 'django-concat'
    def __init__(self, secret_key, salt=None, sep='.', key_derivation=None,
                 digest_method=None, algorithm=None):
        self.secret_key = want_bytes(secret_key)
        self.sep = sep
        self.salt = 'itsdangerous.Signer' if salt is None else salt
        if key_derivation is None:
            key_derivation = self.default_key_derivation
        self.key_derivation = key_derivation
        if digest_method is None:
            digest_method = self.default_digest_method
        self.digest_method = digest_method
        if algorithm is None:
            algorithm = HMACAlgorithm(self.digest_method)
        self.algorithm = algorithm

总结一下, signer = self.make_signer(salt, self.algorithm), singer是Singer类的一个实例,singer的属性如下

singer.secret_key = app.config['SECRET_KEY']

singer.sep = '.'

singer.salt = b'itsdangerous'

singer.key_derivation = 'django-concat'

singer.digest_method = staticmethod(hashlib.sha1)

singer.algorithm = HMACAlgorithm(hashlib.sha256)


(3) return signer.sign(self.dump_payload(header, obj))

上文提到,header = {‘alg’: 'HS256', 'iat': 当前时间, 'exp': 过期时间}

obj = {'confirm': 23}

1.dump_payload函数

    def dump_payload(self, header, obj):
        base64d_header = base64_encode(self.serializer.dumps(header))
        base64d_payload = base64_encode(self.serializer.dumps(obj))
        return base64d_header + b'.' + base64d_payload
    1.1self.serializer.dumps(header)

        实例属性self.serializer = json

        所以这就就等价于json.dumps({‘alg’: 'HS256', 'iat': 当前时间, 'exp': 过期时间})

        json.dumps把字典转化成str类型, 然后用base64_encode对这个str进行编码。


    所以dump_payload函数返回的就是header字典的字符串base64编码 + obj字典的字符串的base64编码 中间用 ‘.’进行分隔


2.signer.sign函数:

    def sign(self, value):
        """Signs the given string."""
        return value + want_bytes(self.sep) + self.get_signature(value)

value就是上面dump_payload的返回值

    2.1 get_signature函数:

    def get_signature(self, value):
        """Returns the signature for the given value"""
        value = want_bytes(value)
        key = self.derive_key()
        sig = self.algorithm.get_signature(key, value)
        return base64_encode(sig)

        2.1.1   key = self.derive_key()

    def derive_key(self):
        """This method is called to derive the key.  If you're unhappy with
        the default key derivation choices you can override them here.
        Keep in mind that the key derivation in itsdangerous is not intended
        to be used as a security method to make a complex key out of a short
        password.  Instead you should use large random secret keys.
        """
        salt = want_bytes(self.salt)
        if self.key_derivation == 'concat':
            return self.digest_method(salt + self.secret_key).digest()
        elif self.key_derivation == 'django-concat':
            return self.digest_method(salt + b'signer' +
                self.secret_key).digest()
        elif self.key_derivation == 'hmac':
            mac = hmac.new(self.secret_key, digestmod=self.digest_method)
            mac.update(salt)
            return mac.digest()
        elif self.key_derivation == 'none':
            return self.secret_key
        else:
            raise TypeError('Unknown key derivation method')
 
           前文我们提到self.key_derivation == 'django-concat', 所以执行  return self.digest_method(salt + b'signer' +self.secret_key).digest()

           上文提到self.digest_method = staticmethod(hashlib.sha1)

           所以上上句就等价于staticmethod(hashlib.sha1)(salt + b'signer' +self.secret_key).digest()

           等价于 hashlib.sha1(b'itsdangerous' + b'signer' + app.config['SECRECT_KEY']).digest()

           这就代码意思就是对参数字符串进行sha1加密, 返回加密后的字符串。


     key = b'itsdangerous' + b'signer' + app.config['SECRECT_KEY']  sha1加密后的字符串。


    2.1.2 sig = self.algrothm.get_signature(key, value)  

        实例属性self.algrothm = HMACAlgorithm(hashlib.sha256) 所以self.algrothm.get_signature(key, value) 等价于

          HMACAlgorithm(hashlib.sha256).get_signature(key, value)

         1. HMACAlgorithm的构造函数:

class HMACAlgorithm(SigningAlgorithm):
    default_digest_method = staticmethod(hashlib.sha1)
    def __init__(self, digest_method=None):
        if digest_method is None:
            digest_method = self.default_digest_method
        self.digest_method = digest_method

         HMACAlgorithm(hashlib.sha256)创建了HMACAlgorithm类的一个实例, 并设置实例属性digest_method = hashlib.sha256

        2.紧接着这个实例调用get_signature方法:

    def get_signature(self, key, value):
        mac = hmac.new(key, msg=value, digestmod=self.digest_method)
        return mac.digest()

            hmac键值对加密, key作为键, value 作为值, 用hashlib.sha256进行加密,所以

       sig = self.algrothm.get_signature(key, value) = key作为键, value 作为值, 用hashlib.sha256进行加密后的字符串


所以2.1 get_signature函数返回的是对sig base64编码后的字符串


所以2signer.sign函数返回的是

return value + want_bytes(self.sep) + self.get_signature(value)


所以dumps函数返回的就是, header字典的字符串base64编码 + obj字典的字符串的base64编码 中间用 ‘.’进行分隔 (value)+  ‘.’  + key作为键, value 作为值, 用hashlib.sha256进行加密后的字符串的base64编码    也就是token!


data = s.loads(token)我们留到下次讲...







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值