import jwt
import datetime
from flask import request, g
from .http import fail_response
from flask import has_request_context
from functools import wraps
from ...models import User
import re
from typing import Union
JWT_CONFIG: dict[str, Union[str, datetime.timedelta]] = {
'ACCESS_TIMEOUT': datetime.timedelta(minutes=15),
'REFRESH_TIMEOUT': datetime.timedelta(minutes=60),
'KEY': 'ABC', # 加密钥匙
'ALGORITHM': 'HS256', # 加密类型
'USER_ID_FILED': 'id', # 查询的用户id名
'AUTH_HEADER_TYPES': 'Bearer' # 接收权限标头1
}
class AnonymousUserMixin:
"""
This is the default object for representing an anonymous user.
"""
@property
def is_authenticated(self):
return False
@property
def is_active(self):
return False
@property
def is_anonymous(self):
return True
def get_id(self):
return
# 获取用户
def get_user():
if has_request_context():
if "jwt_user" not in g:
# current_app.login_manager._load_user()
return AnonymousUserMixin() # 匿名用户
return g.jwt_user
return None
# 通过用户名和密码获取用户
def check_user(username, password):
user = User.query.filter(User.username == username).first()
if not user:
return fail_response({'msg': '用户名错误', 'username': username})
if not user.validate_password(password):
return fail_response({'msg': '密码错误', 'password': password})
return user
# 通过id获取用户
def jwt_filter_user(id: int):
user = User.query.filter(User.id == id).first()
if not user:
return fail_response({'msg': '不存在的用户id', 'pk': id})
return user
# 装饰器: 获取请求头的 Bearer
def headersauth(func):
@wraps(func)
def wrapper(*args, **kwargs):
if token := re.match(r'{0}\s(?P<token>.*)'.format(JWT_CONFIG.get('AUTH_HEADER_TYPES', 'Bearer')), str(request.headers.get('Authorization'))):
token = flask_jwt.access(access=token.group('token'))
id = token.get(JWT_CONFIG.get('USER_ID_FILED'))
g.jwt_user = jwt_filter_user(int(id))
else:
return fail_response({'msg': '没有提供认证'})
return func(*args, **kwargs)
return wrapper
class MyTokenJwt:
def __init__(self, access_timeout, refresh_timeout, algorithm, key) -> None:
# self.now = datetime.datetime.now(tz=datetime.timezone.utc) # 当前时间
self.access_timeout = access_timeout or datetime.timedelta(
minutes=15) # access令牌超时时间
self.refresh_timeout = refresh_timeout or datetime.timedelta(
minutes=60) # refresh令牌超时时间
self.key = key # 加盐值
self.algorithm = algorithm # 使用的加密算法
# 签证(access, refresh)
def visa(self, **kwargs):
return {'access': self.jwt_encode(self.access_timeout, token_type='access', **kwargs), 'refresh': self.jwt_encode(self.refresh_timeout, token_type='refresh', **kwargs)}
# 用于access令牌认证
def access(self, token):
return self.jwt_decode(token, token_type='access')
# 用于refresh刷新令牌认证
def refresh(self, token):
token = self.jwt_decode(token, token_type='refresh')
return {'token': self.jwt_encode(**token)}
# 用于jwt加密, 返回令牌
def jwt_encode(self, token_timeout=JWT_CONFIG['REFRESH_TIMEOUT'], **kwargs):
now = datetime.datetime.now(tz=datetime.timezone.utc)
payload = {**kwargs}
payload['exp'] = now + token_timeout
payload['iat'] = now
payload.pop('password', None)
return jwt.encode(payload=payload, key=self.key, algorithm=self.algorithm)
# 用户jwt解密, 返回字典
def jwt_decode(self, token: str, token_type=None):
try:
token_dict = jwt.decode(jwt=token, key=self.key,
algorithms=[self.algorithm])
if token_type and token_type != token_dict.get('token_type'):
return fail_response({'error_token': '令牌类型错误'})
except jwt.ExpiredSignatureError:
return fail_response({'error_token': '签证已经过期'})
except jwt.exceptions.DecodeError:
return fail_response({'error_token': 'token是必须的'})
return token_dict
flask_jwt = MyTokenJwt(access_timeout=JWT_CONFIG.get('ACCESS_TIMEOUT'), refresh_timeout=JWT_CONFIG.get(
'REFRESH_TIMEOUT'), key=JWT_CONFIG.get('KEY'), algorithm=JWT_CONFIG.get('ALGORITHM'))
# print(my_token.visa(username='陈海峰'))
# print(my_token.access('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2ODA2MjI0NDIsImlhdCI6MTY4MDYxODg0MiwidG9rZW5fdHlwZSI6InJlZnJlc2giLCJ1c2VybmFtZSI6Ilx1OTY0OFx1NmQ3N1x1NWNmMCJ9.Fi23bQHpAfZRm7Efd-Q7PHtBH7gUsYwHkkPoTtOJap0'))
[ Flask自定义jwt_token ]
发表评论
177 views