django 生成token 单独py文件生成方法
djangocoresigning.py
import base64 import hashlib import hmac import json import re import time import zlib import datetime from decimal import Decimal # SECRET_KEY = '来自django.core.signing文件中' SECRET_KEY = 'django-insecure-$4!p1prf($^)rh6$r%6d37q6=d3^iotlxa+b*5jtz9ljm#5y9u' _SEP_UNSAFE = re.compile(r'^[A-z0-9-_=]*$') _PROTECTED_TYPES = ( type(None), int, float, Decimal, datetime.datetime, datetime.date, datetime.time, ) # Copyright (c) 2010 Guilherme Gondim. All rights reserved. # Copyright (c) 2009 Simon Willison. All rights reserved. # Copyright (c) 2002 Drew Perttula. All rights reserved. # # License: # Python Software Foundation License version 2 # # See the file "LICENSE" for terms & conditions for usage, and a DISCLAIMER OF # ALL WARRANTIES. # # This Baseconv distribution contains no GNU General Public Licensed (GPLed) # code so it may be used in proprietary projects just like prior ``baseconv`` # distributions. # # All trademarks referenced herein are property of their respective holders. # """ Convert numbers from base 10 integers to base X strings and back again. Sample usage:: >>> base20 = BaseConverter('0123456789abcdefghij') >>> base20.encode(1234) '31e' >>> base20.decode('31e') 1234 >>> base20.encode(-1234) '-31e' >>> base20.decode('-31e') -1234 >>> base11 = BaseConverter('0123456789-', sign='$') >>> base11.encode('$1234') '$-22' >>> base11.decode('$-22') '$1234' """ BASE2_ALPHABET = '01' BASE16_ALPHABET = '0123456789ABCDEF' BASE56_ALPHABET = '23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz' BASE36_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz' BASE62_ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' BASE64_ALPHABET = BASE62_ALPHABET + '-_' class BaseConverter: decimal_digits = '0123456789' def __init__(self, digits, sign='-'): self.sign = sign self.digits = digits if sign in self.digits: raise ValueError('Sign character found in converter base digits.') def __repr__(self): return "<%s: base%s (%s)>" % (self.__class__.__name__, len(self.digits), self.digits) def encode(self, i): neg, value = self.convert(i, self.decimal_digits, self.digits, '-') if neg: return self.sign + value return value def decode(self, s): neg, value = self.convert(s, self.digits, self.decimal_digits, self.sign) if neg: value = '-' + value return int(value) def convert(self, number, from_digits, to_digits, sign): if str(number)[0] == sign: number = str(number)[1:] neg = 1 else: neg = 0 # make an integer out of the number x = 0 for digit in str(number): x = x * len(from_digits) + from_digits.index(digit) # create the result in base 'len(to_digits)' if x == 0: res = to_digits[0] else: res = '' while x > 0: digit = x % len(to_digits) res = to_digits[digit] + res x = int(x // len(to_digits)) return neg, res base2 = BaseConverter(BASE2_ALPHABET) base16 = BaseConverter(BASE16_ALPHABET) base36 = BaseConverter(BASE36_ALPHABET) base56 = BaseConverter(BASE56_ALPHABET) base62 = BaseConverter(BASE62_ALPHABET) # base64 = BaseConverter(BASE64_ALPHABET, sign='$') class BadSignature(Exception): """Signature does not match.""" pass class SignatureExpired(BadSignature): """Signature timestamp is older than required max_age.""" pass def is_protected_type(obj): """Determine if the object instance is of a protected type. Objects of protected types are preserved as-is when passed to force_text(strings_only=True). """ return isinstance(obj, _PROTECTED_TYPES) class Promise: """ Base class for the proxy class created in the closure of the lazy function. It's used to recognize promises in code. """ pass def force_bytes(s, encoding='utf-8', strings_only=False, errors='strict'): """ Similar to smart_bytes, except that lazy instances are resolved to strings, rather than kept as lazy objects. If strings_only is True, don't convert (some) non-string-like objects. """ # Handle the common case first for performance reasons. if isinstance(s, bytes): if encoding == 'utf-8': return s else: return s.decode('utf-8', errors).encode(encoding, errors) if strings_only and is_protected_type(s): return s if isinstance(s, memoryview): return bytes(s) if isinstance(s, Promise) or not isinstance(s, str): return str(s).encode(encoding, errors) else: return s.encode(encoding, errors) def b64_encode(s): return base64.urlsafe_b64encode(s).strip(b'=') def b64_decode(s): pad = b'=' * (-len(s) % 4) return base64.urlsafe_b64decode(s + pad) def salted_hmac(key_salt, value, secret=None): """ Return the HMAC-SHA1 of 'value', using a key generated from key_salt and a secret (which defaults to settings.SECRET_KEY). A different key_salt should be passed in for every application of HMAC. """ if secret is None: secret = SECRET_KEY key_salt = force_bytes(key_salt) secret = force_bytes(secret) # We need to generate a derived key from our base key. We can do this by # passing the key_salt and our base key through a pseudo-random function and # SHA1 works nicely. key = hashlib.sha1(key_salt + secret).digest() # If len(key_salt + secret) > sha_constructor().block_size, the above # line is redundant and could be replaced by key = key_salt + secret, since # the hmac module does the same thing for keys longer than the block size. # However, we need to ensure that we *always* do this. return hmac.new(key, msg=force_bytes(value), digestmod=hashlib.sha1) def base64_hmac(salt, value, key): return b64_encode(salted_hmac(salt, value, key).digest()).decode() class JSONSerializer: """ Simple wrapper around json to be used in signing.dumps and signing.loads. """ def dumps(self, obj): return json.dumps(obj, separators=(',', ':')).encode('latin-1') def loads(self, data): return json.loads(data.decode('latin-1')) def dumps(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) if len(compressed) < (len(data) - 1): data = compressed is_compressed = True base64d = b64_encode(data).decode() if is_compressed: base64d = '.' + base64d return TimestampSigner(key, salt=salt).sign(base64d) def loads(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 = force_bytes(TimestampSigner(key, salt=salt).unsign(s, max_age=max_age)) decompress = False if base64d[:1] == b'.': # It's compressed; uncompress it first base64d = base64d[1:] decompress = True data = b64_decode(base64d) if decompress: data = zlib.decompress(data) return serializer().loads(data) def constant_time_compare(val1, val2): """Return True if the two strings are equal, False otherwise.""" return hmac.compare_digest(force_bytes(val1), force_bytes(val2)) class Signer: def __init__(self, key=None, sep=':', salt=None): # Use of native strings in all versions of Python self.key = key or SECRET_KEY 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__) def signature(self, value): return base64_hmac(self.salt + 'signer', value, self.key) def sign(self, value): return '%s%s%s' % (value, self.sep, self.signature(value)) def unsign(self, signed_value): if self.sep not in signed_value: raise BadSignature('No "%s" found in value' % self.sep) value, sig = signed_value.rsplit(self.sep, 1) return value # print('306行', value) # print('306行', sig) # print('306行', self.signature(value)) # print('306行', constant_time_compare(sig, self.signature(value))) # if constant_time_compare(sig, self.signature(value)): # return value # raise BadSignature('Signature "%s" does not match' % sig) class TimestampSigner(Signer): def timestamp(self): return base62.encode(int(time.time())) def sign(self, value): value = '%s%s%s' % (value, self.sep, self.timestamp()) return super().sign(value) def unsign(self, value, max_age=None): """ Retrieve original value and check it wasn't signed more than max_age seconds ago. """ result = super().unsign(value) print('325行', result) value, timestamp = result.rsplit(self.sep, 1) # timestamp = baseconv.base62.decode(timestamp) timestamp = base62.decode(timestamp) if max_age is not None: if isinstance(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
encryption_decryption.py
import os import sys curry_dir = os.path.dirname(os.path.abspath(__file__)) # 当前目录 libsPath = os.path.abspath(os.path.join(curry_dir)) # djangocoresigning.py文件在同一目录下 sys.path.append(libsPath) from djangocoresigning import dumps, loads from djangocoresigning import b64_encode, b64_decode # 加密,生成token def encrypt(user, key=None, salt=None): # token = djangocoresigning.dumps(user, key=SECRET_KEY, salt=salt) # token = djangocoresigning.b64_encode(token.encode()).decode() token = dumps(user, key=key, salt=salt) token = b64_encode(token.encode()).decode() return token # 解密,返回用户名密码 def decrypt(token, key=None, salt=None): # user = djangocoresigning.b64_decode(token.encode()).decode() # user = djangocoresigning.loads(user, key=SECRET_KEY, salt=salt) user = b64_decode(token.encode()).decode() user = loads(user, key=key, salt=salt) return user if __name__ == '__main__': user = { 'username': 'admin', 'password': '123456', } # salt = 'token' SECRET_KEY = 'django-insecure-$4!p1prf($^)rh6$r%6d37q6=d3^iotlxa+b*5jtz9ljm#5y9u' # e = encrypt(user, SECRET_KEY) e = 'ZXlKMWMyVnlibUZ0WlNJNkltRmtiV2x1SWl3aWNHRnpjM2R2Y21RaU9pSXhNak0wTlRZaWZROjFtS3haMDpGaUowanFlcUg3TThDdk1YQnh1Sm5QZXEyRDA' d = decrypt(e, SECRET_KEY) print('加密', e) print('解密', d)