这个模块主要用来签名和序列化

使用场景:

一、给字符串添加签名:

  发送方和接收方拥有相同的密钥--"secret-key",发送方使用密钥对发送内容进行签名,接收方使用相同的密钥对接收到的内容进行验证,看是否是发送方发送的内容

 1 >>> from itsdangerous import Signer
 2 >>> s = Signer('secret-key')
 3 >>> s.sign('my string, ssssssssss,dddddddddddddlsd')
 4 'my string, ssssssssss,dddddddddddddlsd.nSXTxgO_UMN4gkLZcFCioa-dZSo'
 5 >>>
 6 >>> s.unsign('my string, ssssssssss,dddddddddddddlsd.nSXTxgO_UMN4gkLZcFCioa-dZSo')
 7 'my string, ssssssssss,dddddddddddddlsd'
 8 >>> s.unsign('my string, ssss.nSXTxgO_UMN4gkLZcFCioa-dZSo')
 9 Traceback (most recent call last):
10   File "<stdin>", line 1, in <module>
11   File "/usr/local/lib/python2.7/site-packages/itsdangerous.py", line 374, in unsign
12     payload=value)
13 itsdangerous.BadSignature: Signature 'nSXTxgO_UMN4gkLZcFCioa-dZSo' does not match
14 >>> s.unsign('my string, ssssssssss,dddddddddddddlsd.nSXTxgO_UMN4gkLZcFCioa-dZSP')
15 Traceback (most recent call last):
16   File "<stdin>", line 1, in <module>
17   File "/usr/local/lib/python2.7/site-packages/itsdangerous.py", line 374, in unsign
18     payload=value)
19 itsdangerous.BadSignature: Signature 'nSXTxgO_UMN4gkLZcFCioa-dZSP' does not match
20 >>>

二、带时间戳的签名:

  签名有一定的时效性,发送方发送时,带上时间信息,接收方判断多长时间内是否失效

>>> from itsdangerous import TimestampSigner
>>> s = TimestampSigner('secret-key')
>>> string = s.sign('foo')
>>> s.unsign(string, max_age=5)foo>>> s.unsign(string, max_age=5)
Traceback (most recent call last):...
itsdangerous.SignatureExpired: Signature age 15 > 5 seconds

三、序列化

>>> from itsdangerous import Serializer
>>> s = Serializer('secret-key')
>>> s.dumps([1, 2, 3, 4])
'[1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo'
And it can of course also load:>>> s.loads('[1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo')
[1, 2, 3, 4]
If you want to have the timestamp attached you can use the TimedSerializer.

四、带时间戳的序列化:

>>> from itsdangerous import TimedSerializer
>>> s=TimedSerializer('secret-key')
>>> s.dumps([1,2,3,4])
'[1, 2, 3, 4].DI7WHQ.yVOjwQWau5mVRGuVkoqa7654VXc'
>>> s.loads('[1, 2, 3, 4].DI7WHQ.yVOjwQWau5mVRGuVkoqa7654VXc')
[1, 2, 3, 4]
>>> s.loads('[1, 2, 3, 4].DI7WHQ.yVOjwQWau5mVRGuVkoqa7654VXc',max_age=10)
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/usr/local/lib/python2.7/site-packages/itsdangerous.py", line 643, in loads.unsign(s, max_age, return_timestamp=True)File "/usr/local/lib/python2.7/site-packages/itsdangerous.py", line 463, in unsigndate_signed=self.timestamp_to_datetime(timestamp))
itsdangerous.SignatureExpired: Signature age 28 > 10 seconds
>>> s.loads('[1, 2, 3, 4].DI7WHQ.yVOjwQWau5mVRGuVkoqa7654VXc',max_age=40)
[1, 2, 3, 4]
>>>

五、URL安全序列化

对于限定字符串的场景,你可以使用URL安全序列化

>>> from itsdangerous import URLSafeSerializer
>>> s = URLSafeSerializer('secret-key')
>>> s.dumps([1, 2, 3, 4])
'WzEsMiwzLDRd.wSPHqC0gR7VUqivlSukJ0IeTDgo'
>>> s.loads('WzEsMiwzLDRd.wSPHqC0gR7VUqivlSukJ0IeTDgo')
[1, 2, 3, 4]

六、JSON Web签名

JSON Web Signatures

Starting with “itsdangerous” 0.18 JSON Web Signatures are also supported. They generally work very similar to the already existing URL safe serializer but will emit headers according to the current draft (10) of the JSON Web Signature (JWS) [draft-ietf-jose-json-web-signature].

>>> from itsdangerous import JSONWebSignatureSerializer
>>> s = JSONWebSignatureSerializer('secret-key')
>>> s.dumps({'x': 42})
'eyJhbGciOiJIUzI1NiJ9.eyJ4Ijo0Mn0.ZdTn1YyGz9Yx5B5wNpWRL221G1WpVE5fPCPKNuc6UAo'

When loading the value back the header will not be returned by default like with the other serializers. However it is possible to also ask for the header by passing return_header=True. Custom header fields can be provided upon serialization:

>>> s.dumps(0, header_fields={'v': 1}) 'eyJhbGciOiJIUzI1NiIsInYiOjF9.MA.wT-RZI9YU06R919VBdAfTLn82_iIQD70J_j-3F4z_aM' >>> s.loads('eyJhbGciOiJIUzI1NiIsInYiOjF9.MA.wT-RZI9YU06R919VBdAf' ... 'TLn82_iIQD70J_j-3F4z_aM', return_header=True) ... (0, {u'alg': u'HS256', u'v': 1}) 

“itsdangerous” only provides HMAC SHA derivatives and the none algorithm at the moment and does not support the ECC based ones. The algorithm in the header is checked against the one of the serializer and on a mismatch a BadSignatureexception is raised.

七、带时间戳的JSON Web签名

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
s = Serializer('secret-key', expires_in=60)
s.dumps({'id': user.id}) # user为model中封装过的对象

 

八、盐值

这里的盐值和加密算法里的盐值概念不一样,这里的盐值(salt)可以应用到上面所有情形中,不同的盐值,生成的签名或者序列化的数值不一样

>>> s1 = URLSafeSerializer('secret-key', salt='activate-salt')
>>> s1.dumps(42)
'NDI.kubVFOOugP5PAIfEqLJbXQbfTxs'
>>> s2 = URLSafeSerializer('secret-key', salt='upgrade-salt')
>>> s2.dumps(42)
'NDI.7lx-N1P-z2veJ7nT1_2bnTkjGTE'
>>> s2.loads(s1.dumps(42))
Traceback (most recent call last):...
itsdangerous.BadSignature: Signature "kubVFOOugP5PAIfEqLJbXQbfTxs" does not match
Only the serializer with the same salt can load the value:>>> s2.loads(s2.dumps(42))
42

九、源码奉上:

  1 # -*- coding: utf-8 -*-
  2 """
  3     itsdangerous
  4     ~~~~~~~~~~~~
  5
  6     A module that implements various functions to deal with untrusted
  7     sources.  Mainly useful for web applications.
  8
  9     :copyright: (c) 2014 by Armin Ronacher and the Django Software Foundation.
 10     :license: BSD, see LICENSE for more details.
 11 """
 12
 13 import sys
 14 import hmac
 15 import zlib
 16 import time
 17 import base64
 18 import hashlib
 19 import operator
 20 from datetime import datetime
 21
 22
 23 PY2 = sys.version_info[0] == 2
 24 if PY2:
 25     from itertools import izip
 26     text_type = unicode
 27     int_to_byte = chr
 28     number_types = (int, long, float)
 29 else:
 30     from functools import reduce
 31     izip = zip
 32     text_type = str
 33     int_to_byte = operator.methodcaller('to_bytes', 1, 'big')
 34     number_types = (int, float)
 35
 36
 37 try:
 38     import simplejson as json
 39 except ImportError:
 40     import json
 41
 42
 43 class _CompactJSON(object):
 44     """Wrapper around simplejson that strips whitespace.
 45     """
 46
 47     def loads(self, payload):
 48         return json.loads(payload)
 49
 50     def dumps(self, obj):
 51         return json.dumps(obj, separators=(',', ':'))
 52
 53
 54 compact_json = _CompactJSON()
 55
 56
 57 # 2011/01/01 in UTC
 58 EPOCH = 1293840000
 59
 60
 61 def want_bytes(s, encoding='utf-8', errors='strict'):
 62     if isinstance(s, text_type):
 63         s = s.encode(encoding, errors)
 64     return s
 65
 66
 67 def is_text_serializer(serializer):
 68     """Checks wheather a serializer generates text or binary."""
 69     return isinstance(serializer.dumps({}), text_type)
 70
 71
 72 # Starting with 3.3 the standard library has a c-implementation for
 73 # constant time string compares.
 74 _builtin_constant_time_compare = getattr(hmac, 'compare_digest', None)
 75
 76
 77 def constant_time_compare(val1, val2):
 78     """Returns True if the two strings are equal, False otherwise.
 79
 80     The time taken is independent of the number of characters that match.  Do
 81     not use this function for anything else than comparision with known
 82     length targets.
 83
 84     This is should be implemented in C in order to get it completely right.
 85     """
 86     if _builtin_constant_time_compare is not None:
 87         return _builtin_constant_time_compare(val1, val2)
 88     len_eq = len(val1) == len(val2)
 89     if len_eq:
 90         result = 0
 91         left = val1
 92     else:
 93         result = 1
 94         left = val2
 95     for x, y in izip(bytearray(left), bytearray(val2)):
 96         result |= x ^ y
 97     return result == 0
 98
 99
100 class BadData(Exception):
101     """Raised if bad data of any sort was encountered.  This is the
102     base for all exceptions that itsdangerous is currently using.
103
104     .. versionadded:: 0.15
105     """
106     message = None
107
108     def __init__(self, message):
109         Exception.__init__(self, message)
110         self.message = message
111
112     def __str__(self):
113         return text_type(self.message)
114
115     if PY2:
116         __unicode__ = __str__
117         def __str__(self):
118             return self.__unicode__().encode('utf-8')
119
120
121 class BadPayload(BadData):
122     """This error is raised in situations when payload is loaded without
123     checking the signature first and an exception happend as a result of
124     that.  The original exception that caused that will be stored on the
125     exception as :attr:`original_error`.
126
127     This can also happen with a :class:`JSONWebSignatureSerializer` that
128     is subclassed and uses a different serializer for the payload than
129     the expected one.
130
131     .. versionadded:: 0.15
132     """
133
134     def __init__(self, message, original_error=None):
135         BadData.__init__(self, message)
136         #: If available, the error that indicates why the payload
137         #: was not valid.  This might be `None`.
138         self.original_error = original_error
139
140
141 class BadSignature(BadData):
142     """This error is raised if a signature does not match.  As of
143     itsdangerous 0.14 there are helpful attributes on the exception
144     instances.  You can also catch down the baseclass :exc:`BadData`.
145     """
146
147     def __init__(self, message, payload=None):
148         BadData.__init__(self, message)
149         #: The payload that failed the signature test.  In some
150         #: situations you might still want to inspect this, even if
151         #: you know it was tampered with.
152         #:
153         #: .. versionadded:: 0.14
154         self.payload = payload
155
156
157 class BadTimeSignature(BadSignature):
158     """Raised for time based signatures that fail.  This is a subclass
159     of :class:`BadSignature` so you can catch those down as well.
160     """
161
162     def __init__(self, message, payload=None, date_signed=None):
163         BadSignature.__init__(self, message, payload)
164
165         #: If the signature expired this exposes the date of when the
166         #: signature was created.  This can be helpful in order to
167         #: tell the user how long a link has been gone stale.
168         #:
169         #: .. versionadded:: 0.14
170         self.date_signed = date_signed
171
172
173 class BadHeader(BadSignature):
174     """Raised if a signed header is invalid in some form.  This only
175     happens for serializers that have a header that goes with the
176     signature.
177
178     .. versionadded:: 0.24
179     """
180
181     def __init__(self, message, payload=None, header=None,
182                  original_error=None):
183         BadSignature.__init__(self, message, payload)
184
185         #: If the header is actually available but just malformed it
186         #: might be stored here.
187         self.header = header
188
189         #: If available, the error that indicates why the payload
190         #: was not valid.  This might be `None`.
191         self.original_error = original_error
192
193
194 class SignatureExpired(BadTimeSignature):
195     """Signature timestamp is older than required max_age.  This is a
196     subclass of :exc:`BadTimeSignature` so you can use the baseclass for
197     catching the error.
198     """
199
200
201 def base64_encode(string):
202     """base64 encodes a single bytestring (and is tolerant to getting
203     called with a unicode string).
204     The resulting bytestring is safe for putting into URLs.
205     """
206     string = want_bytes(string)
207     return base64.urlsafe_b64encode(string).strip(b'=')
208
209
210 def base64_decode(string):
211     """base64 decodes a single bytestring (and is tolerant to getting
212     called with a unicode string).
213     The result is also a bytestring.
214     """
215     string = want_bytes(string, encoding='ascii', errors='ignore')
216     return base64.urlsafe_b64decode(string + b'=' * (-len(string) % 4))
217
218
219 def int_to_bytes(num):
220     assert num >= 0
221     rv = []
222     while num:
223         rv.append(int_to_byte(num & 0xff))
224         num >>= 8
225     return b''.join(reversed(rv))
226
227
228 def bytes_to_int(bytestr):
229     return reduce(lambda a, b: a << 8 | b, bytearray(bytestr), 0)
230
231
232 class SigningAlgorithm(object):
233     """Subclasses of `SigningAlgorithm` have to implement `get_signature` to
234     provide signature generation functionality.
235     """
236
237     def get_signature(self, key, value):
238         """Returns the signature for the given key and value"""
239         raise NotImplementedError()
240
241     def verify_signature(self, key, value, sig):
242         """Verifies the given signature matches the expected signature"""
243         return constant_time_compare(sig, self.get_signature(key, value))
244
245
246 class NoneAlgorithm(SigningAlgorithm):
247     """This class provides a algorithm that does not perform any signing and
248     returns an empty signature.
249     """
250
251     def get_signature(self, key, value):
252         return b''
253
254
255 class HMACAlgorithm(SigningAlgorithm):
256     """This class provides signature generation using HMACs."""
257
258     #: The digest method to use with the MAC algorithm.  This defaults to sha1
259     #: but can be changed for any other function in the hashlib module.
260     default_digest_method = staticmethod(hashlib.sha1)
261
262     def __init__(self, digest_method=None):
263         if digest_method is None:
264             digest_method = self.default_digest_method
265         self.digest_method = digest_method
266
267     def get_signature(self, key, value):
268         mac = hmac.new(key, msg=value, digestmod=self.digest_method)
269         return mac.digest()
270
271
272 class Signer(object):
273     """This class can sign bytes and unsign it and validate the signature
274     provided.
275
276     Salt can be used to namespace the hash, so that a signed string is only
277     valid for a given namespace.  Leaving this at the default value or re-using
278     a salt value across different parts of your application where the same
279     signed value in one part can mean something different in another part
280     is a security risk.
281
282     See :ref:`the-salt` for an example of what the salt is doing and how you
283     can utilize it.
284
285     .. versionadded:: 0.14
286        `key_derivation` and `digest_method` were added as arguments to the
287        class constructor.
288
289     .. versionadded:: 0.18
290         `algorithm` was added as an argument to the class constructor.
291     """
292
293     #: The digest method to use for the signer.  This defaults to sha1 but can
294     #: be changed for any other function in the hashlib module.
295     #:
296     #: .. versionchanged:: 0.14
297     default_digest_method = staticmethod(hashlib.sha1)
298
299     #: Controls how the key is derived.  The default is Django style
300     #: concatenation.  Possible values are ``concat``, ``django-concat``
301     #: and ``hmac``.  This is used for deriving a key from the secret key
302     #: with an added salt.
303     #:
304     #: .. versionadded:: 0.14
305     default_key_derivation = 'django-concat'
306
307     def __init__(self, secret_key, salt=None, sep='.', key_derivation=None,
308                  digest_method=None, algorithm=None):
309         self.secret_key = want_bytes(secret_key)
310         self.sep = sep
311         self.salt = 'itsdangerous.Signer' if salt is None else salt
312         if key_derivation is None:
313             key_derivation = self.default_key_derivation
314         self.key_derivation = key_derivation
315         if digest_method is None:
316             digest_method = self.default_digest_method
317         self.digest_method = digest_method
318         if algorithm is None:
319             algorithm = HMACAlgorithm(self.digest_method)
320         self.algorithm = algorithm
321
322     def derive_key(self):
323         """This method is called to derive the key.  If you're unhappy with
324         the default key derivation choices you can override them here.
325         Keep in mind that the key derivation in itsdangerous is not intended
326         to be used as a security method to make a complex key out of a short
327         password.  Instead you should use large random secret keys.
328         """
329         salt = want_bytes(self.salt)
330         if self.key_derivation == 'concat':
331             return self.digest_method(salt + self.secret_key).digest()
332         elif self.key_derivation == 'django-concat':
333             return self.digest_method(salt + b'signer' +
334                 self.secret_key).digest()
335         elif self.key_derivation == 'hmac':
336             mac = hmac.new(self.secret_key, digestmod=self.digest_method)
337             mac.update(salt)
338             return mac.digest()
339         elif self.key_derivation == 'none':
340             return self.secret_key
341         else:
342             raise TypeError('Unknown key derivation method')
343
344     def get_signature(self, value):
345         """Returns the signature for the given value"""
346         value = want_bytes(value)
347         key = self.derive_key()
348         sig = self.algorithm.get_signature(key, value)
349         return base64_encode(sig)
350
351     def sign(self, value):
352         """Signs the given string."""
353         return value + want_bytes(self.sep) + self.get_signature(value)
354
355     def verify_signature(self, value, sig):
356         """Verifies the signature for the given value."""
357         key = self.derive_key()
358         try:
359             sig = base64_decode(sig)
360         except Exception:
361             return False
362         return self.algorithm.verify_signature(key, value, sig)
363
364     def unsign(self, signed_value):
365         """Unsigns the given string."""
366         signed_value = want_bytes(signed_value)
367         sep = want_bytes(self.sep)
368         if sep not in signed_value:
369             raise BadSignature('No %r found in value' % self.sep)
370         value, sig = signed_value.rsplit(sep, 1)
371         if self.verify_signature(value, sig):
372             return value
373         raise BadSignature('Signature %r does not match' % sig,
374                            payload=value)
375
376     def validate(self, signed_value):
377         """Just validates the given signed value.  Returns `True` if the
378         signature exists and is valid, `False` otherwise."""
379         try:
380             self.unsign(signed_value)
381             return True
382         except BadSignature:
383             return False
384
385
386 class TimestampSigner(Signer):
387     """Works like the regular :class:`Signer` but also records the time
388     of the signing and can be used to expire signatures.  The unsign
389     method can rause a :exc:`SignatureExpired` method if the unsigning
390     failed because the signature is expired.  This exception is a subclass
391     of :exc:`BadSignature`.
392     """
393
394     def get_timestamp(self):
395         """Returns the current timestamp.  This implementation returns the
396         seconds since 1/1/2011.  The function must return an integer.
397         """
398         return int(time.time() - EPOCH)
399
400     def timestamp_to_datetime(self, ts):
401         """Used to convert the timestamp from `get_timestamp` into a
402         datetime object.
403         """
404         return datetime.utcfromtimestamp(ts + EPOCH)
405
406     def sign(self, value):
407         """Signs the given string and also attaches a time information."""
408         value = want_bytes(value)
409         timestamp = base64_encode(int_to_bytes(self.get_timestamp()))
410         sep = want_bytes(self.sep)
411         value = value + sep + timestamp
412         return value + sep + self.get_signature(value)
413
414     def unsign(self, value, max_age=None, return_timestamp=False):
415         """Works like the regular :meth:`~Signer.unsign` but can also
416         validate the time.  See the base docstring of the class for
417         the general behavior.  If `return_timestamp` is set to `True`
418         the timestamp of the signature will be returned as naive
419         :class:`datetime.datetime` object in UTC.
420         """
421         try:
422             result = Signer.unsign(self, value)
423             sig_error = None
424         except BadSignature as e:
425             sig_error = e
426             result = e.payload or b''
427         sep = want_bytes(self.sep)
428
429         # If there is no timestamp in the result there is something
430         # seriously wrong.  In case there was a signature error, we raise
431         # that one directly, otherwise we have a weird situation in which
432         # we shouldn't have come except someone uses a time-based serializer
433         # on non-timestamp data, so catch that.
434         if not sep in result:
435             if sig_error:
436                 raise sig_error
437             raise BadTimeSignature('timestamp missing', payload=result)
438
439         value, timestamp = result.rsplit(sep, 1)
440         try:
441             timestamp = bytes_to_int(base64_decode(timestamp))
442         except Exception:
443             timestamp = None
444
445         # Signature is *not* okay.  Raise a proper error now that we have
446         # split the value and the timestamp.
447         if sig_error is not None:
448             raise BadTimeSignature(text_type(sig_error), payload=value,
449                                    date_signed=timestamp)
450
451         # Signature was okay but the timestamp is actually not there or
452         # malformed.  Should not happen, but well.  We handle it nonetheless
453         if timestamp is None:
454             raise BadTimeSignature('Malformed timestamp', payload=value)
455
456         # Check timestamp is not older than max_age
457         if max_age is not None:
458             age = self.get_timestamp() - timestamp
459             if age > max_age:
460                 raise SignatureExpired(
461                     'Signature age %s > %s seconds' % (age, max_age),
462                     payload=value,
463                     date_signed=self.timestamp_to_datetime(timestamp))
464
465         if return_timestamp:
466             return value, self.timestamp_to_datetime(timestamp)
467         return value
468
469     def validate(self, signed_value, max_age=None):
470         """Just validates the given signed value.  Returns `True` if the
471         signature exists and is valid, `False` otherwise."""
472         try:
473             self.unsign(signed_value, max_age=max_age)
474             return True
475         except BadSignature:
476             return False
477
478
479 class Serializer(object):
480     """This class provides a serialization interface on top of the
481     signer.  It provides a similar API to json/pickle and other modules but is
482     slightly differently structured internally.  If you want to change the
483     underlying implementation for parsing and loading you have to override the
484     :meth:`load_payload` and :meth:`dump_payload` functions.
485
486     This implementation uses simplejson if available for dumping and loading
487     and will fall back to the standard library's json module if it's not
488     available.
489
490     Starting with 0.14 you do not need to subclass this class in order to
491     switch out or customer the :class:`Signer`.  You can instead also pass a
492     different class to the constructor as well as keyword arguments as
493     dictionary that should be forwarded::
494
495         s = Serializer(signer_kwargs={'key_derivation': 'hmac'})
496
497     .. versionchanged:: 0.14:
498        The `signer` and `signer_kwargs` parameters were added to the
499        constructor.
500     """
501
502     #: If a serializer module or class is not passed to the constructor
503     #: this one is picked up.  This currently defaults to :mod:`json`.
504     default_serializer = json
505
506     #: The default :class:`Signer` class that is being used by this
507     #: serializer.
508     #:
509     #: .. versionadded:: 0.14
510     default_signer = Signer
511
512     def __init__(self, secret_key, salt=b'itsdangerous', serializer=None,
513                  signer=None, signer_kwargs=None):
514         self.secret_key = want_bytes(secret_key)
515         self.salt = want_bytes(salt)
516         if serializer is None:
517             serializer = self.default_serializer
518         self.serializer = serializer
519         self.is_text_serializer = is_text_serializer(serializer)
520         if signer is None:
521             signer = self.default_signer
522         self.signer = signer
523         self.signer_kwargs = signer_kwargs or {}
524
525     def load_payload(self, payload, serializer=None):
526         """Loads the encoded object.  This function raises :class:`BadPayload`
527         if the payload is not valid.  The `serializer` parameter can be used to
528         override the serializer stored on the class.  The encoded payload is
529         always byte based.
530         """
531         if serializer is None:
532             serializer = self.serializer
533             is_text = self.is_text_serializer
534         else:
535             is_text = is_text_serializer(serializer)
536         try:
537             if is_text:
538                 payload = payload.decode('utf-8')
539             return serializer.loads(payload)
540         except Exception as e:
541             raise BadPayload('Could not load the payload because an '
542                 'exception occurred on unserializing the data',
543                 original_error=e)
544
545     def dump_payload(self, obj):
546         """Dumps the encoded object.  The return value is always a
547         bytestring.  If the internal serializer is text based the value
548         will automatically be encoded to utf-8.
549         """
550         return want_bytes(self.serializer.dumps(obj))
551
552     def make_signer(self, salt=None):
553         """A method that creates a new instance of the signer to be used.
554         The default implementation uses the :class:`Signer` baseclass.
555         """
556         if salt is None:
557             salt = self.salt
558         return self.signer(self.secret_key, salt=salt, **self.signer_kwargs)
559
560     def dumps(self, obj, salt=None):
561         """Returns a signed string serialized with the internal serializer.
562         The return value can be either a byte or unicode string depending
563         on the format of the internal serializer.
564         """
565         payload = want_bytes(self.dump_payload(obj))
566         rv = self.make_signer(salt).sign(payload)
567         if self.is_text_serializer:
568             rv = rv.decode('utf-8')
569         return rv
570
571     def dump(self, obj, f, salt=None):
572         """Like :meth:`dumps` but dumps into a file.  The file handle has
573         to be compatible with what the internal serializer expects.
574         """
575         f.write(self.dumps(obj, salt))
576
577     def loads(self, s, salt=None):
578         """Reverse of :meth:`dumps`, raises :exc:`BadSignature` if the
579         signature validation fails.
580         """
581         s = want_bytes(s)
582         return self.load_payload(self.make_signer(salt).unsign(s))
583
584     def load(self, f, salt=None):
585         """Like :meth:`loads` but loads from a file."""
586         return self.loads(f.read(), salt)
587
588     def loads_unsafe(self, s, salt=None):
589         """Like :meth:`loads` but without verifying the signature.  This is
590         potentially very dangerous to use depending on how your serializer
591         works.  The return value is ``(signature_okay, payload)`` instead of
592         just the payload.  The first item will be a boolean that indicates
593         if the signature is okay (``True``) or if it failed.  This function
594         never fails.
595
596         Use it for debugging only and if you know that your serializer module
597         is not exploitable (eg: do not use it with a pickle serializer).
598
599         .. versionadded:: 0.15
600         """
601         return self._loads_unsafe_impl(s, salt)
602
603     def _loads_unsafe_impl(self, s, salt, load_kwargs=None,
604                            load_payload_kwargs=None):
605         """Lowlevel helper function to implement :meth:`loads_unsafe` in
606         serializer subclasses.
607         """
608         try:
609             return True, self.loads(s, salt=salt, **(load_kwargs or {}))
610         except BadSignature as e:
611             if e.payload is None:
612                 return False, None
613             try:
614                 return False, self.load_payload(e.payload,
615                     **(load_payload_kwargs or {}))
616             except BadPayload:
617                 return False, None
618
619     def load_unsafe(self, f, *args, **kwargs):
620         """Like :meth:`loads_unsafe` but loads from a file.
621
622         .. versionadded:: 0.15
623         """
624         return self.loads_unsafe(f.read(), *args, **kwargs)
625
626
627 class TimedSerializer(Serializer):
628     """Uses the :class:`TimestampSigner` instead of the default
629     :meth:`Signer`.
630     """
631
632     default_signer = TimestampSigner
633
634     def loads(self, s, max_age=None, return_timestamp=False, salt=None):
635         """Reverse of :meth:`dumps`, raises :exc:`BadSignature` if the
636         signature validation fails.  If a `max_age` is provided it will
637         ensure the signature is not older than that time in seconds.  In
638         case the signature is outdated, :exc:`SignatureExpired` is raised
639         which is a subclass of :exc:`BadSignature`.  All arguments are
640         forwarded to the signer's :meth:`~TimestampSigner.unsign` method.
641         """
642         base64d, timestamp = self.make_signer(salt) \
643             .unsign(s, max_age, return_timestamp=True)
644         payload = self.load_payload(base64d)
645         if return_timestamp:
646             return payload, timestamp
647         return payload
648
649     def loads_unsafe(self, s, max_age=None, salt=None):
650         load_kwargs = {'max_age': max_age}
651         load_payload_kwargs = {}
652         return self._loads_unsafe_impl(s, salt, load_kwargs, load_payload_kwargs)
653
654
655 class JSONWebSignatureSerializer(Serializer):
656     """This serializer implements JSON Web Signature (JWS) support.  Only
657     supports the JWS Compact Serialization.
658     """
659
660     jws_algorithms = {
661         'HS256': HMACAlgorithm(hashlib.sha256),
662         'HS384': HMACAlgorithm(hashlib.sha384),
663         'HS512': HMACAlgorithm(hashlib.sha512),
664         'none': NoneAlgorithm(),
665     }
666
667     #: The default algorithm to use for signature generation
668     default_algorithm = 'HS256'
669
670     default_serializer = compact_json
671
672     def __init__(self, secret_key, salt=None, serializer=None,
673                  signer=None, signer_kwargs=None, algorithm_name=None):
674         Serializer.__init__(self, secret_key, salt, serializer,
675                             signer, signer_kwargs)
676         if algorithm_name is None:
677             algorithm_name = self.default_algorithm
678         self.algorithm_name = algorithm_name
679         self.algorithm = self.make_algorithm(algorithm_name)
680
681     def load_payload(self, payload, return_header=False):
682         payload = want_bytes(payload)
683         if b'.' not in payload:
684             raise BadPayload('No "." found in value')
685         base64d_header, base64d_payload = payload.split(b'.', 1)
686         try:
687             json_header = base64_decode(base64d_header)
688         except Exception as e:
689             raise BadHeader('Could not base64 decode the header because of '
690                 'an exception', original_error=e)
691         try:
692             json_payload = base64_decode(base64d_payload)
693         except Exception as e:
694             raise BadPayload('Could not base64 decode the payload because of '
695                 'an exception', original_error=e)
696         try:
697             header = Serializer.load_payload(self, json_header,
698                 serializer=json)
699         except BadData as e:
700             raise BadHeader('Could not unserialize header because it was '
701                 'malformed', original_error=e)
702         if not isinstance(header, dict):
703             raise BadHeader('Header payload is not a JSON object',
704                 header=header)
705         payload = Serializer.load_payload(self, json_payload)
706         if return_header:
707             return payload, header
708         return payload
709
710     def dump_payload(self, header, obj):
711         base64d_header = base64_encode(self.serializer.dumps(header))
712         base64d_payload = base64_encode(self.serializer.dumps(obj))
713         return base64d_header + b'.' + base64d_payload
714
715     def make_algorithm(self, algorithm_name):
716         try:
717             return self.jws_algorithms[algorithm_name]
718         except KeyError:
719             raise NotImplementedError('Algorithm not supported')
720
721     def make_signer(self, salt=None, algorithm=None):
722         if salt is None:
723             salt = self.salt
724         key_derivation = 'none' if salt is None else None
725         if algorithm is None:
726             algorithm = self.algorithm
727         return self.signer(self.secret_key, salt=salt, sep='.',
728             key_derivation=key_derivation, algorithm=algorithm)
729
730     def make_header(self, header_fields):
731         header = header_fields.copy() if header_fields else {}
732         header['alg'] = self.algorithm_name
733         return header
734
735     def dumps(self, obj, salt=None, header_fields=None):
736         """Like :meth:`~Serializer.dumps` but creates a JSON Web Signature.  It
737         also allows for specifying additional fields to be included in the JWS
738         Header.
739         """
740         header = self.make_header(header_fields)
741         signer = self.make_signer(salt, self.algorithm)
742         return signer.sign(self.dump_payload(header, obj))
743
744     def loads(self, s, salt=None, return_header=False):
745         """Reverse of :meth:`dumps`. If requested via `return_header` it will
746         return a tuple of payload and header.
747         """
748         payload, header = self.load_payload(
749             self.make_signer(salt, self.algorithm).unsign(want_bytes(s)),
750             return_header=True)
751         if header.get('alg') != self.algorithm_name:
752             raise BadHeader('Algorithm mismatch', header=header,
753                             payload=payload)
754         if return_header:
755             return payload, header
756         return payload
757
758     def loads_unsafe(self, s, salt=None, return_header=False):
759         kwargs = {'return_header': return_header}
760         return self._loads_unsafe_impl(s, salt, kwargs, kwargs)
761
762
763 class TimedJSONWebSignatureSerializer(JSONWebSignatureSerializer):
764     """Works like the regular :class:`JSONWebSignatureSerializer` but also
765     records the time of the signing and can be used to expire signatures.
766
767     JWS currently does not specify this behavior but it mentions a possibility
768     extension like this in the spec.  Expiry date is encoded into the header
769     similarily as specified in `draft-ietf-oauth-json-web-token
770     <http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#expDef`_.
771
772     The unsign method can raise a :exc:`SignatureExpired` method if the
773     unsigning failed because the signature is expired.  This exception is a
774     subclass of :exc:`BadSignature`.
775     """
776
777     DEFAULT_EXPIRES_IN = 3600
778
779     def __init__(self, secret_key, expires_in=None, **kwargs):
780         JSONWebSignatureSerializer.__init__(self, secret_key, **kwargs)
781         if expires_in is None:
782             expires_in = self.DEFAULT_EXPIRES_IN
783         self.expires_in = expires_in
784
785     def make_header(self, header_fields):
786         header = JSONWebSignatureSerializer.make_header(self, header_fields)
787         iat = self.now()
788         exp = iat + self.expires_in
789         header['iat'] = iat
790         header['exp'] = exp
791         return header
792
793     def loads(self, s, salt=None, return_header=False):
794         payload, header = JSONWebSignatureSerializer.loads(
795             self, s, salt, return_header=True)
796
797         if 'exp' not in header:
798             raise BadSignature('Missing expiry date', payload=payload)
799
800         if not (isinstance(header['exp'], number_types)
801                 and header['exp'] > 0):
802             raise BadSignature('expiry date is not an IntDate',
803                                payload=payload)
804
805         if header['exp'] < self.now():
806             raise SignatureExpired('Signature expired', payload=payload,
807                                    date_signed=self.get_issue_date(header))
808
809         if return_header:
810             return payload, header
811         return payload
812
813     def get_issue_date(self, header):
814         rv = header.get('iat')
815         if isinstance(rv, number_types):
816             return datetime.utcfromtimestamp(int(rv))
817
818     def now(self):
819         return int(time.time())
820
821
822 class URLSafeSerializerMixin(object):
823     """Mixed in with a regular serializer it will attempt to zlib compress
824     the string to make it shorter if necessary.  It will also base64 encode
825     the string so that it can safely be placed in a URL.
826     """
827
828     def load_payload(self, payload):
829         decompress = False
830         if payload.startswith(b'.'):
831             payload = payload[1:]
832             decompress = True
833         try:
834             json = base64_decode(payload)
835         except Exception as e:
836             raise BadPayload('Could not base64 decode the payload because of '
837                 'an exception', original_error=e)
838         if decompress:
839             try:
840                 json = zlib.decompress(json)
841             except Exception as e:
842                 raise BadPayload('Could not zlib decompress the payload before '
843                     'decoding the payload', original_error=e)
844         return super(URLSafeSerializerMixin, self).load_payload(json)
845
846     def dump_payload(self, obj):
847         json = super(URLSafeSerializerMixin, self).dump_payload(obj)
848         is_compressed = False
849         compressed = zlib.compress(json)
850         if len(compressed) < (len(json) - 1):
851             json = compressed
852             is_compressed = True
853         base64d = base64_encode(json)
854         if is_compressed:
855             base64d = b'.' + base64d
856         return base64d
857
858
859 class URLSafeSerializer(URLSafeSerializerMixin, Serializer):
860     """Works like :class:`Serializer` but dumps and loads into a URL
861     safe string consisting of the upper and lowercase character of the
862     alphabet as well as ``'_'``, ``'-'`` and ``'.'``.
863     """
864     default_serializer = compact_json
865
866
867 class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer):
868     """Works like :class:`TimedSerializer` but dumps and loads into a URL
869     safe string consisting of the upper and lowercase character of the
870     alphabet as well as ``'_'``, ``'-'`` and ``'.'``.
871     """
872     default_serializer = compact_json

itsdangerous.py

refer:

1、https://pythonhosted.org/itsdangerous/

2、http://itsdangerous.readthedocs.io/en/latest/

3、http://cxymrzero.github.io/blog/2015/03/18/flask-token/

python的模块itsdangerous相关推荐

  1. Python Re 模块超全解读!详细

    内行必看!Python Re 模块超全解读! 2019.08.08 18:59:45字数 953阅读 121 re模块下的函数 compile(pattern):创建模式对象 > import ...

  2. python argparse模块_Python argparse模块应用实例解析

    这篇文章主要介绍了Python argparse模块应用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 简介 argparse是python ...

  3. 关于使用python logging模块的几点总结

    关于使用python logging模块的几点总结 使用python的标准日志模块logging可以非常方便地记录日志.Python日志系统非常丰富.添加结构化或非结构化日志输出到python代码,写 ...

  4. python高级-模块(14)

    一.python中的模块 有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt函数,必须用语句#include <math.h>引入math.h这个头文件,否则是无法正常进行调用的. ...

  5. 转载: Python os 模块的功能以及子函数介绍

    原文链接: python之os模块 - 程序生(Codey) - 博客园 https://www.cnblogs.com/cxscode/p/8085326.html 一.Python OS模块介绍 ...

  6. 简单介绍python process模块

    在python中大部分情况需要使用多进程,python提供了multiprocessing模块.multiprocessing模块的功能众多:支持子进程.通信和共享数据.执行不同形式的同步,提供了Pr ...

  7. python io模块_python中的StringIO模块

    原博文 2015-10-23 15:21 − # python中的StringIO模块 标签:python StringIO --- > 此模块主要用于在内存缓冲区中读写数据.模块是用类编写的, ...

  8. python正则表达式需要模块_使用Python正则表达式模块,让操作更加简单

    处理文本数据的一个主要任务就是创建许多以文本为基础的特性. 人们可能想要在文本中找出特定格式的内容,比如找出存在于文本中的电子邮件,或者大型文本中的电话号码. 虽然想要实现上述功能听起来很繁琐,但是如 ...

  9. python导入模块有同名_Python:导入与函数同名的模块

    背景:第一次在SE上提问.我在 Python方面还很陌生,而且在编程方面也不是很有经验.我已经四处寻找,但我没有找到这个问题的答案,我非常感谢你的帮助. 我的问题是:如何导入与函数同名的模块? 具体来 ...

最新文章

  1. java将本地图片转为bas64_JAVA将图片(本地或者网络资源)转为Base64字符串
  2. 如何修改数据库表或存储过程的所有者
  3. Vue_template是什么
  4. 第八次作业——系统设计与团队分配(个人)
  5. 解读Facebook CAN:如何给人工智能赋予艺术创作的力量
  6. Java虚拟机组成详解
  7. 2020年4月数据库流行度排行:MySQL 成事实王者,国产openGauss引期待
  8. Ubuntu 16.04 Steam
  9. C++ 获取本机登陆过的QQ号码
  10. 现有产品的三种发展战略
  11. 左右方块消除html5,html5消除方块游戏总结-对象
  12. matlab之svd、svds函数
  13. 涨姿势,原来程序员喝酒都是这样的呀
  14. 安装python版opencv遇到ModuleNotFoundError: No module named ‘skbuild‘
  15. CSDN下载码如何使用以及免积分下载
  16. PL/SQL基础入门,史上最全的教程
  17. Photoshop插件-创建所有亮度通道蒙板-脚本开发-PS插件
  18. Week 2 Sequence Labelling
  19. 涉密计算机杀毒记录表,保密工作自检自查记录表
  20. Kotlin里的takeIf和takeUnless

热门文章

  1. 做出仿iphone的圆角效果,以及shpe的各个属性
  2. HCNE题库附件、可下载
  3. 通过命令行在Python中测试以太坊RPC客户端
  4. PHP原生处理select结果集的函数介绍
  5. MySQL升级教程(CentOS)
  6. 引导加载程序之争: LILO 和 GRUB
  7. 为什么世界上一些最好的科学家和程序员,在世人眼里,都有点不太正常,甚至行为混乱...
  8. 我的第一个 JSP (SSH) 个人网站【开源】
  9. Arch Linux 安装 Xerox Phaser 3125N 网络打印机备忘录
  10. linux下安装svn