使用itsdangerous生成确认令牌
来源:互联网 发布:access数据库管理工具 编辑:程序博客网 时间:2024/06/08 11:27
首先我们来看生成令牌和解码令牌的代码:
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'
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_payload1.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)我们留到下次讲...
- 使用itsdangerous生成确认令牌
- Flask学习总结笔记(11) -- 利用itsdangerous实现用户身份确认
- java.security.MessageDigest的使用(2),生成安全令牌!
- java.security.MessageDigest的使用(2),生成安全令牌!
- thinkphp 表单令牌使用
- 用flask开发个人博客(33)—— 使用itsdangerous进行账户的确认
- Struts2中的Token令牌使用
- Struts2中的Token令牌使用
- RSA令牌动态口令生成原理
- ThinkPHP无法自动生成表单令牌问题
- 生成一个固定长度的令牌token
- 令牌的生成和验证工具类
- 使用安全令牌连接VPN网络-windows7
- Struts1.x中的令牌(Token)使用
- 拿来主义(QQ令牌的另一种使用)
- Struts1.x中的令牌(Token)使用
- ACE:使用令牌作为递归互斥锁
- Struts1.x中的令牌(Token)使用
- 扶持创业不是“囤屯桌子”
- 媒体人创业常遇青春期“综合症” :合伙人,融资及商业运营
- 有家,有X6&X6Plus,快才有意义:《vivo陪你快•乐回家》
- I Think I Need a Houseboat
- 平衡二叉树
- 使用itsdangerous生成确认令牌
- Error calling Driver#connect错误原因
- vs2015配置opencv3.1
- springboot2入门(3-maven相关)
- jsp的两种跳转方式和区别
- 前端面试题(不定期更新)
- P
- 王阳明心学 之 心即理感悟
- oracle中NVL()和NVL()2函数的作用和区别