defdumps(obj, key=None, salt='django.core.signing', serializer=JSONSerializer, compress=False): """ Return URL-safe, hmac/SHA1 signed base64 compressed JSON string. If key is None, use settings.SECRET_KEY instead.
If compress is True (not the default), check if compressing using zlib can save some space. Prepend a '.' to signify compression. This is included in the signature, to protect against zip bombs.
Salt can be used to namespace the hash, so that a signed string is only valid for a given namespace. Leaving this at the default value or re-using a salt value across different parts of your application without good cause is a security risk.
The serializer is expected to return a bytestring. """ data = serializer().dumps(obj) # 使用选定的类进行序列化
# Flag for if it's been compressed or not is_compressed = False
# 数据压缩处理 if compress: # Avoid zlib dependency unless compress is being used compressed = zlib.compress(data) iflen(compressed) len(data) - 1): data = compressed is_compressed = True base64d = b64_encode(data).decode() # base64编码 decode转化成字符串 if is_compressed: base64d = '.' + base64d return TimestampSigner(key, salt=salt).sign(base64d) # 返回一个签名值
# loads的过程为dumps的逆过程 defloads(s, key=None, salt='django.core.signing', serializer=JSONSerializer, max_age=None): """ Reverse of dumps(), raise BadSignature if signature fails.
The serializer is expected to accept a bytestring. """ # TimestampSigner.unsign() returns str but base64 and zlib compression # operate on bytes. base64d = TimestampSigner(key, salt=salt).unsign(s, max_age=max_age).encode() decompress = base64d[:1] == b'.' if decompress: # It's compressed; uncompress it first base64d = base64d[1:] data = b64_decode(base64d) if decompress: data = zlib.decompress(data) return serializer().loads(data)
看看两个签名的类:
在Signer类中中:
classSigner:
def__init__(self, key=None, sep=':', salt=None): # Use of native strings in all versions of Python self.key = key or settings.SECRET_KEY # key默认为settings中的配置项 self.sep = sep if _SEP_UNSAFE.match(self.sep): raise ValueError( 'Unsafe Signer separator: %r (cannot be empty or consist of ' 'only A-z0-9-_=)' % sep, ) self.salt = salt or'%s.%s' % (self.__class__.__module__, self.__class__.__name__)
defunsign(self, signed_value): if self.sep notin signed_value: raise BadSignature('No "%s" found in value' % self.sep) value, sig = signed_value.rsplit(self.sep, 1) if constant_time_compare(sig, self.signature(value)): return value raise BadSignature('Signature "%s" does not match' % sig)
defsign(self, value): value = '%s%s%s' % (value, self.sep, self.timestamp()) returnsuper().sign(value)
defunsign(self, value, max_age=None): """ Retrieve original value and check it wasn't signed more than max_age seconds ago. """ result = super().unsign(value) value, timestamp = result.rsplit(self.sep, 1) timestamp = baseconv.base62.decode(timestamp) if max_age isnotNone: ifisinstance(max_age, datetime.timedelta): max_age = max_age.total_seconds() # Check timestamp is not older than max_age age = time.time() - timestamp if age > max_age: raise SignatureExpired( 'Signature age %s > %s seconds' % (age, max_age)) return value
import os import django.core.signing import requests
# from Django.contrib.sessions.serializers.PickleSerializer import pickle classPickleSerializer: """ Simple wrapper around pickle to be used in signing.dumps and signing.loads. """ protocol = pickle.HIGHEST_PROTOCOL