lesscode-flask 0.2.38__tar.gz → 0.2.39__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/PKG-INFO +1 -1
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/__init__.py +37 -12
- lesscode-flask-0.2.39/lesscode_flask/utils/limit/req/rate_limiter_handler.py +88 -0
- lesscode-flask-0.2.39/lesscode_flask/utils/limit/req_count/count_limiter_handler.py +84 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask.egg-info/PKG-INFO +1 -1
- lesscode-flask-0.2.38/lesscode_flask/utils/limit/req/rate_limiter_handler.py +0 -58
- lesscode-flask-0.2.38/lesscode_flask/utils/limit/req_count/count_limiter_handler.py +0 -57
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/README.md +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/app.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/db/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/db/datasource.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/db/executor.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/export_data/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/export_data/data_download_handler.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/log/access_log_handler.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/model/access_log.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/model/base_model.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/model/parameterized_query.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/model/resource_param_template.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/model/response_result.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/model/user.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/model/user_limit_policy.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/service/access_log_service.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/service/base_service.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/service/resource_param_template_service.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/setting/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/setup/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/signals.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/static/swagger.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/decorator/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/decorator/cache.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/decorator/sql_injection.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/decorator/swagger.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/dify_utils.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/file/file_exporter.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/file/file_utils.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/fs_util.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/helpers.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/json/NotSortJSONProvider.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/limit/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/limit/consecutive/consecutive_limiter_handler.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/limit/consecutive/redis_consecutive_limiter.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/limit/limit_util.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/limit/req/redis_rate_limiter.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/limit/req_count/redis_count_limiter.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/oss/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/oss/aliyun_oss.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/oss/ks3_oss.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/oss/minio_oss.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/redis/redis_helper.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/request/request.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/swagger/swagger_template.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/swagger/swagger_util.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/task/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/task/task_helper.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/thread/thread_utils.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/wsgi.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask.egg-info/SOURCES.txt +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask.egg-info/dependency_links.txt +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask.egg-info/requires.txt +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask.egg-info/top_level.txt +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/query_runner/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/query_runner/clickhouse.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/query_runner/elasticsearch.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/query_runner/kingbase.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/query_runner/mysql.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/query_runner/pg.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/settings/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/settings/helpers.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/utils/__init__.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/redash/utils/requests_session.py +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/setup.cfg +0 -0
- {lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/setup.py +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
__version__ =
|
|
1
|
+
__version__ = "0.2.39"
|
|
2
2
|
|
|
3
3
|
import functools
|
|
4
4
|
import logging
|
|
@@ -17,8 +17,16 @@ class SQ_Blueprint(Blueprint):
|
|
|
17
17
|
kwargs["import_name"] = __name__
|
|
18
18
|
super().__init__(name=name, url_prefix=url_prefix, **kwargs)
|
|
19
19
|
|
|
20
|
-
def decorator_handler(
|
|
21
|
-
|
|
20
|
+
def decorator_handler(
|
|
21
|
+
self,
|
|
22
|
+
title: str,
|
|
23
|
+
url: str = None,
|
|
24
|
+
cache_enalbe: bool = False,
|
|
25
|
+
cache_ex: int = 3600 * 10,
|
|
26
|
+
content_type: str = "json",
|
|
27
|
+
methods=["POST"],
|
|
28
|
+
export_enable: bool = False,
|
|
29
|
+
):
|
|
22
30
|
options = {"methods": methods}
|
|
23
31
|
|
|
24
32
|
def decorator(func):
|
|
@@ -41,9 +49,7 @@ class SQ_Blueprint(Blueprint):
|
|
|
41
49
|
# 如果没有开启缓存,或者缓存未命中,则执行原始函数
|
|
42
50
|
data = func(*args, **kwargs)
|
|
43
51
|
if isinstance(data, dict) and export_enable:
|
|
44
|
-
data.update({
|
|
45
|
-
"download_key": download_key
|
|
46
|
-
})
|
|
52
|
+
data.update({"download_key": download_key})
|
|
47
53
|
return data
|
|
48
54
|
|
|
49
55
|
wrapper._title = title
|
|
@@ -54,12 +60,31 @@ class SQ_Blueprint(Blueprint):
|
|
|
54
60
|
|
|
55
61
|
return decorator
|
|
56
62
|
|
|
57
|
-
def post_route(
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
def post_route(
|
|
64
|
+
self,
|
|
65
|
+
title: str,
|
|
66
|
+
url: str = None,
|
|
67
|
+
cache_enalbe: bool = False,
|
|
68
|
+
cache_ex: int = 3600 * 10,
|
|
69
|
+
content_type: str = "json",
|
|
70
|
+
methods=["POST"],
|
|
71
|
+
export_enable: bool = False,
|
|
72
|
+
):
|
|
73
|
+
decorator = self.decorator_handler(
|
|
74
|
+
title, url, cache_enalbe, cache_ex, content_type, methods, export_enable
|
|
75
|
+
)
|
|
60
76
|
return decorator
|
|
61
77
|
|
|
62
|
-
def get_route(
|
|
63
|
-
|
|
64
|
-
|
|
78
|
+
def get_route(
|
|
79
|
+
self,
|
|
80
|
+
title: str,
|
|
81
|
+
url: str = None,
|
|
82
|
+
cache_enalbe: bool = False,
|
|
83
|
+
cache_ex: int = 3600 * 10,
|
|
84
|
+
content_type: str = "json",
|
|
85
|
+
methods=["GET"],
|
|
86
|
+
):
|
|
87
|
+
decorator = self.decorator_handler(
|
|
88
|
+
title, url, cache_enalbe, cache_ex, content_type, methods
|
|
89
|
+
)
|
|
65
90
|
return decorator
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
from flask import current_app, request
|
|
6
|
+
|
|
7
|
+
from lesscode_flask.model.response_result import ResponseResult
|
|
8
|
+
from lesscode_flask.model.user import flask_login
|
|
9
|
+
from lesscode_flask.utils.fs_util import fs_webhook
|
|
10
|
+
from lesscode_flask.utils.redis.redis_helper import RedisHelper
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RateLimitHandler:
|
|
16
|
+
"""
|
|
17
|
+
限流后的处理函数实现
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, req, delay: float, excess: float):
|
|
21
|
+
"""
|
|
22
|
+
初始化
|
|
23
|
+
:param req:
|
|
24
|
+
:param delay: 延迟时间
|
|
25
|
+
:param excess: 超出数量
|
|
26
|
+
"""
|
|
27
|
+
self.req = req
|
|
28
|
+
self.delay = delay
|
|
29
|
+
self.excess = excess
|
|
30
|
+
|
|
31
|
+
def response_handler(self):
|
|
32
|
+
# 如果配置了飞书 webhook URL,则发送告警通知
|
|
33
|
+
# 收集用户相关信息
|
|
34
|
+
current_user = flask_login.current_user
|
|
35
|
+
fs_oam_service_url = current_app.config.get("FS_OAM_SERVICE_URL")
|
|
36
|
+
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
|
37
|
+
lock_account_url = (
|
|
38
|
+
f"{fs_oam_service_url}/icp/authUser/lock_account?id={current_user.id}"
|
|
39
|
+
)
|
|
40
|
+
logout_url = f"{fs_oam_service_url}/icp/oauth/logout_token?token={token}"
|
|
41
|
+
|
|
42
|
+
# 发送 GET 请求到 lock_account_url
|
|
43
|
+
try:
|
|
44
|
+
lock_response = requests.get(lock_account_url, timeout=30)
|
|
45
|
+
logger.info(
|
|
46
|
+
"Lock account request sent, status: %s", lock_response.status_code
|
|
47
|
+
)
|
|
48
|
+
except requests.RequestException as e:
|
|
49
|
+
logger.error("Failed to send lock account request: %s", str(e))
|
|
50
|
+
|
|
51
|
+
# 发送 GET 请求到 logout_url
|
|
52
|
+
try:
|
|
53
|
+
logout_response = requests.get(logout_url, timeout=30)
|
|
54
|
+
logger.info("Logout request sent, status: %s", logout_response.status_code)
|
|
55
|
+
except requests.RequestException as e:
|
|
56
|
+
logger.error("Failed to send logout request: %s", str(e))
|
|
57
|
+
|
|
58
|
+
limit_fs_webhook_url = current_app.config.get("LIMIT_FS_WEBHOOK_URL")
|
|
59
|
+
# 如果配置了飞书 webhook URL,则发送告警通知
|
|
60
|
+
if limit_fs_webhook_url:
|
|
61
|
+
content = []
|
|
62
|
+
current_user = flask_login.current_user
|
|
63
|
+
# 收集用户相关信息
|
|
64
|
+
content.append(
|
|
65
|
+
{"tag": "text", "text": f"用户名称:{current_user.display_name}\n"}
|
|
66
|
+
)
|
|
67
|
+
phone_no = (
|
|
68
|
+
current_user.phone_no if current_user.phone_no is not None else "-"
|
|
69
|
+
)
|
|
70
|
+
content.append({"tag": "text", "text": f"手机号:{phone_no}\n"})
|
|
71
|
+
content.append({"tag": "text", "text": f"用户IP:{request.remote_addr}\n"})
|
|
72
|
+
content.append({"tag": "text", "text": f"资源地址:{request.path}\n"})
|
|
73
|
+
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
|
74
|
+
if token:
|
|
75
|
+
FS_OAM_SERVICE_URL = current_app.config.get("FS_OAM_SERVICE_URL")
|
|
76
|
+
content.append({"tag": "text", "text": "运维处理:"})
|
|
77
|
+
# lock_account_url = f"{FS_OAM_SERVICE_URL}/icp/authUser/lock_account?id={current_user.id}"
|
|
78
|
+
# url = f"{FS_OAM_SERVICE_URL}/icp/oauth/logout_token?token={token}"
|
|
79
|
+
# content.append({"tag": "a","text": "强制下线","href": f"{url}"})
|
|
80
|
+
# content.append({"tag": "a", "text": " 禁止登录 ", "href": f"{lock_account_url}"})
|
|
81
|
+
ban_ip_url = f"{FS_OAM_SERVICE_URL}/icp/accessLog/ban_ip?ip={request.remote_addr}"
|
|
82
|
+
content.append({"tag": "a", "text": "封禁IP ", "href": f"{ban_ip_url}"})
|
|
83
|
+
|
|
84
|
+
# 发送飞书 webhook 告警
|
|
85
|
+
fs_webhook(limit_fs_webhook_url, "触发频率限流告警", content)
|
|
86
|
+
return ResponseResult.fail(
|
|
87
|
+
status_code="403", http_code="403", message="请求过于频繁,请稍后再试!"
|
|
88
|
+
)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
from flask import current_app, request
|
|
5
|
+
|
|
6
|
+
from lesscode_flask.model.response_result import ResponseResult
|
|
7
|
+
from lesscode_flask.model.user import flask_login
|
|
8
|
+
from lesscode_flask.utils.fs_util import fs_webhook
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CountLimitHandler:
|
|
14
|
+
"""
|
|
15
|
+
限流后的处理函数实现
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, req, remaining):
|
|
19
|
+
self.req = req
|
|
20
|
+
self.remaining = remaining
|
|
21
|
+
|
|
22
|
+
def response_handler(self):
|
|
23
|
+
"""
|
|
24
|
+
处理请求频率超限的响应
|
|
25
|
+
|
|
26
|
+
该函数用于当用户请求过于频繁触发限流时,返回相应的错误响应。
|
|
27
|
+
同时会发送告警信息到飞书 webhook,记录相关用户和请求信息。
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
ResponseResult: 包含403状态码和错误信息的响应结果
|
|
31
|
+
"""
|
|
32
|
+
# 收集用户相关信息
|
|
33
|
+
current_user = flask_login.current_user
|
|
34
|
+
fs_oam_service_url = current_app.config.get("FS_OAM_SERVICE_URL")
|
|
35
|
+
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
|
36
|
+
lock_account_url = (
|
|
37
|
+
f"{fs_oam_service_url}/icp/authUser/lock_account?id={current_user.id}"
|
|
38
|
+
)
|
|
39
|
+
logout_url = f"{fs_oam_service_url}/icp/oauth/logout_token?token={token}"
|
|
40
|
+
|
|
41
|
+
# 发送 GET 请求到 lock_account_url
|
|
42
|
+
try:
|
|
43
|
+
lock_response = requests.get(lock_account_url, timeout=30)
|
|
44
|
+
logger.info(
|
|
45
|
+
"Lock account request sent, status: %s", lock_response.status_code
|
|
46
|
+
)
|
|
47
|
+
except requests.RequestException as e:
|
|
48
|
+
logger.error("Failed to send lock account request: %s", str(e))
|
|
49
|
+
|
|
50
|
+
# 发送 GET 请求到 logout_url
|
|
51
|
+
try:
|
|
52
|
+
logout_response = requests.get(logout_url, timeout=30)
|
|
53
|
+
logger.info("Logout request sent, status: %s", logout_response.status_code)
|
|
54
|
+
except requests.RequestException as e:
|
|
55
|
+
logger.error("Failed to send logout request: %s", str(e))
|
|
56
|
+
limit_fs_webhook_url = current_app.config.get("LIMIT_FS_WEBHOOK_URL")
|
|
57
|
+
# 如果配置了飞书 webhook URL,则发送告警通知
|
|
58
|
+
if limit_fs_webhook_url:
|
|
59
|
+
content = []
|
|
60
|
+
# 收集用户相关信息
|
|
61
|
+
content.append(
|
|
62
|
+
{"tag": "text", "text": f"用户名称:{current_user.display_name}\n"}
|
|
63
|
+
)
|
|
64
|
+
phone_no = (
|
|
65
|
+
current_user.phone_no if current_user.phone_no is not None else "-"
|
|
66
|
+
)
|
|
67
|
+
content.append({"tag": "text", "text": f"手机号:{phone_no}\n"})
|
|
68
|
+
content.append({"tag": "text", "text": f"用户IP:{request.remote_addr}\n"})
|
|
69
|
+
content.append({"tag": "text", "text": f"资源地址:{request.path}\n"})
|
|
70
|
+
|
|
71
|
+
if token:
|
|
72
|
+
|
|
73
|
+
content.append({"tag": "text", "text": "运维处理:"})
|
|
74
|
+
# content.append({"tag": "a", "text": "强制下线", "href": f"{url}"})
|
|
75
|
+
# content.append({"tag": "a", "text": " 禁止登录 ",
|
|
76
|
+
# "href": f"{lock_account_url}"})
|
|
77
|
+
ban_ip_url = f"{fs_oam_service_url}/icp/accessLog/ban_ip?ip={request.remote_addr}"
|
|
78
|
+
content.append({"tag": "a", "text": "封禁IP ", "href": f"{ban_ip_url}"})
|
|
79
|
+
# 发送飞书 webhook 告警
|
|
80
|
+
fs_webhook(limit_fs_webhook_url, "触发总量限流告警", content)
|
|
81
|
+
|
|
82
|
+
return ResponseResult.fail(
|
|
83
|
+
status_code="403", http_code="403", message="请求过于频繁,请稍后再试!"
|
|
84
|
+
)
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import logging
|
|
3
|
-
|
|
4
|
-
from flask import current_app, request
|
|
5
|
-
|
|
6
|
-
from lesscode_flask.model.response_result import ResponseResult
|
|
7
|
-
from lesscode_flask.model.user import flask_login
|
|
8
|
-
from lesscode_flask.utils.fs_util import fs_webhook
|
|
9
|
-
from lesscode_flask.utils.redis.redis_helper import RedisHelper
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger(__name__)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class RateLimitHandler:
|
|
15
|
-
"""
|
|
16
|
-
限流后的处理函数实现
|
|
17
|
-
"""
|
|
18
|
-
def __init__(self, req, delay: float, excess: float):
|
|
19
|
-
"""
|
|
20
|
-
初始化
|
|
21
|
-
:param req:
|
|
22
|
-
:param delay: 延迟时间
|
|
23
|
-
:param excess: 超出数量
|
|
24
|
-
"""
|
|
25
|
-
self.req = req
|
|
26
|
-
self.delay = delay
|
|
27
|
-
self.excess = excess
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def response_handler(self):
|
|
31
|
-
# 如果配置了飞书 webhook URL,则发送告警通知
|
|
32
|
-
limit_fs_webhook_url = current_app.config.get("LIMIT_FS_WEBHOOK_URL")
|
|
33
|
-
# 如果配置了飞书 webhook URL,则发送告警通知
|
|
34
|
-
if limit_fs_webhook_url:
|
|
35
|
-
content = []
|
|
36
|
-
current_user = flask_login.current_user
|
|
37
|
-
# 收集用户相关信息
|
|
38
|
-
content.append({"tag": "text","text": f"用户名称:{current_user.display_name}\n"})
|
|
39
|
-
phone_no = current_user.phone_no if current_user.phone_no is not None else "-"
|
|
40
|
-
content.append({"tag": "text","text": f"手机号:{phone_no}\n"})
|
|
41
|
-
content.append({"tag": "text","text": f"用户IP:{request.remote_addr}\n"})
|
|
42
|
-
content.append({"tag": "text","text": f"资源地址:{request.path}\n"})
|
|
43
|
-
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
|
44
|
-
if token:
|
|
45
|
-
FS_OAM_SERVICE_URL = current_app.config.get("FS_OAM_SERVICE_URL")
|
|
46
|
-
content.append({"tag": "text","text": f"运维处理:\n"})
|
|
47
|
-
lock_account_url = f"{FS_OAM_SERVICE_URL}/icp/authUser/lock_account?id={current_user.id}"
|
|
48
|
-
url = f"{FS_OAM_SERVICE_URL}/icp/oauth/logout_token?token={token}"
|
|
49
|
-
content.append({"tag": "a","text": "强制下线","href": f"{url}"})
|
|
50
|
-
content.append({"tag": "a", "text": " 禁止登录 ", "href": f"{lock_account_url}"})
|
|
51
|
-
ban_ip_url = f"{FS_OAM_SERVICE_URL}/icp/accessLog/ban_ip?ip={request.remote_addr}"
|
|
52
|
-
content.append({"tag": "a", "text": "封禁IP ", "href": f"{ban_ip_url}"})
|
|
53
|
-
|
|
54
|
-
# 发送飞书 webhook 告警
|
|
55
|
-
fs_webhook(limit_fs_webhook_url, "触发频率限流告警", content)
|
|
56
|
-
return ResponseResult.fail(status_code="403", http_code="403", message="请求过于频繁,请稍后再试!")
|
|
57
|
-
|
|
58
|
-
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
from flask import current_app, request
|
|
4
|
-
|
|
5
|
-
from lesscode_flask.model.response_result import ResponseResult
|
|
6
|
-
from lesscode_flask.model.user import flask_login
|
|
7
|
-
from lesscode_flask.utils.fs_util import fs_webhook
|
|
8
|
-
|
|
9
|
-
logger = logging.getLogger(__name__)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class CountLimitHandler:
|
|
13
|
-
"""
|
|
14
|
-
限流后的处理函数实现
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
def __init__(self, req, remaining):
|
|
18
|
-
self.req = req
|
|
19
|
-
self.remaining = remaining
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def response_handler(self):
|
|
23
|
-
"""
|
|
24
|
-
处理请求频率超限的响应
|
|
25
|
-
|
|
26
|
-
该函数用于当用户请求过于频繁触发限流时,返回相应的错误响应。
|
|
27
|
-
同时会发送告警信息到飞书 webhook,记录相关用户和请求信息。
|
|
28
|
-
|
|
29
|
-
Returns:
|
|
30
|
-
ResponseResult: 包含403状态码和错误信息的响应结果
|
|
31
|
-
"""
|
|
32
|
-
limit_fs_webhook_url = current_app.config.get("LIMIT_FS_WEBHOOK_URL")
|
|
33
|
-
# 如果配置了飞书 webhook URL,则发送告警通知
|
|
34
|
-
if limit_fs_webhook_url:
|
|
35
|
-
content = []
|
|
36
|
-
current_user = flask_login.current_user
|
|
37
|
-
# 收集用户相关信息
|
|
38
|
-
current_user = flask_login.current_user
|
|
39
|
-
# 收集用户相关信息
|
|
40
|
-
content.append({"tag": "text","text": f"用户名称:{current_user.display_name}\n"})
|
|
41
|
-
phone_no = current_user.phone_no if current_user.phone_no is not None else "-"
|
|
42
|
-
content.append({"tag": "text","text": f"手机号:{phone_no}\n"})
|
|
43
|
-
content.append({"tag": "text","text": f"用户IP:{request.remote_addr}\n"})
|
|
44
|
-
content.append({"tag": "text","text": f"资源地址:{request.path}\n"})
|
|
45
|
-
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
|
46
|
-
if token:
|
|
47
|
-
FS_OAM_SERVICE_URL = current_app.config.get("FS_OAM_SERVICE_URL")
|
|
48
|
-
content.append({"tag": "text", "text": f"运维处理:\n"})
|
|
49
|
-
lock_account_url = f"{FS_OAM_SERVICE_URL}/icp/authUser/lock_account?id={current_user.id}"
|
|
50
|
-
url = f"{FS_OAM_SERVICE_URL}/icp/oauth/logout_token?token={token}"
|
|
51
|
-
content.append({"tag": "a", "text": "强制下线", "href": f"{url}"})
|
|
52
|
-
content.append({"tag": "a", "text": " 禁止登录 ", "href": f"{lock_account_url}"})
|
|
53
|
-
ban_ip_url = f"{FS_OAM_SERVICE_URL}/icp/accessLog/ban_ip?ip={request.remote_addr}"
|
|
54
|
-
content.append({"tag": "a", "text": "封禁IP ", "href": f"{ban_ip_url}"})
|
|
55
|
-
# 发送飞书 webhook 告警
|
|
56
|
-
fs_webhook(limit_fs_webhook_url, "触发总量限流告警", content)
|
|
57
|
-
return ResponseResult.fail(status_code="403", http_code="403", message="请求过于频繁,请稍后再试!")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/export_data/data_download_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/model/resource_param_template.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/service/access_log_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/decorator/sql_injection.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/json/NotSortJSONProvider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/limit/req/redis_rate_limiter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/swagger/swagger_template.py
RENAMED
|
File without changes
|
{lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask/utils/swagger/swagger_util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.38 → lesscode-flask-0.2.39}/lesscode_flask.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|