py.lib

Yohn Y. 2022-08-20 Parent:84b54a8a6d4c

38:4f4cc2fc9805 Go to Latest

py.lib/webapp/jwt_util.py

. Полный рефакторинг кода модулей dataclass_utils.py и config_parse_helper.py. Теперь логика предсказуема. + функция dataobj_extract не просто бездумно загоняет данные в класс данных, но имеет функционал проверки данных с возбуждением исключения при разнице (по умолчанию) и принудительного приведения типов.

History
awgur@31 1 # coding: utf-8
awgur@31 2
awgur@31 3 import jwt
awgur@31 4 from datetime import datetime, timedelta
awgur@31 5 from typing import Optional
awgur@31 6
awgur@31 7 JWT_HASH_ALGO = 'HS512'
awgur@31 8
awgur@31 9
awgur@31 10 class JWTError(Exception):
awgur@31 11 pass
awgur@31 12
awgur@31 13
awgur@31 14 class JWTAuthError(JWTError):
awgur@31 15 """\
awgur@31 16 Провалена проверка токена на допустимость по подписи времени или прочее
awgur@31 17 """
awgur@31 18
awgur@31 19
awgur@31 20 class JWTHelper(object):
awgur@31 21 def __init__(self, key: str):
awgur@31 22 self.key = key
awgur@31 23
awgur@31 24 def encode(self, data: dict, timeout: Optional[int] = None) -> str:
awgur@31 25 if timeout is not None:
awgur@31 26 data['exp'] = datetime.utcnow() + timedelta(seconds=timeout)
awgur@31 27
awgur@31 28 return jwt.encode(data, key=self.key, algorithm=JWT_HASH_ALGO)
awgur@31 29
awgur@31 30 def decode(self, token: str, check_timeout: bool = False) -> dict:
awgur@31 31 opts = {
awgur@31 32 'algorithms': [JWT_HASH_ALGO, ]
awgur@31 33 }
awgur@31 34
awgur@31 35 if check_timeout:
awgur@31 36 opts['options'] = {'require': {'exp'}}
awgur@31 37
awgur@31 38 if token is None:
awgur@31 39 raise JWTAuthError('Ключ отсутствует')
awgur@31 40 else:
awgur@31 41 token = token.encode('utf-8')
awgur@31 42
awgur@31 43 try:
awgur@31 44 return jwt.decode(jwt=token, key=self.key, **opts)
awgur@31 45
awgur@31 46 except (jwt.InvalidIssuerError, jwt.InvalidSignatureError, jwt.ExpiredSignatureError) as e:
awgur@31 47 raise JWTAuthError(str(e))
awgur@31 48
awgur@31 49 except jwt.PyJWTError as e:
awgur@31 50 raise JWTError(f'{type(e).__name__}: {e}')
awgur@31 51
awgur@31 52 @classmethod
awgur@31 53 def make_cls_fabric(cls, key: str):
awgur@31 54 def f():
awgur@31 55 return cls(key=key)
awgur@31 56
awgur@34 57 return f