lesscode-flask 0.2.20__tar.gz → 0.2.22__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.20 → lesscode_flask-0.2.22}/PKG-INFO +12 -2
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/__init__.py +1 -1
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/app.py +16 -2
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/model/user_limit_policy.py +4 -1
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/setting/__init__.py +10 -4
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/decorator/cache.py +1 -1
- lesscode_flask-0.2.22/lesscode_flask/utils/limit/consecutive/consecutive_limiter_handler.py +56 -0
- lesscode_flask-0.2.22/lesscode_flask/utils/limit/consecutive/redis_consecutive_limiter.py +71 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask.egg-info/PKG-INFO +12 -2
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask.egg-info/SOURCES.txt +2 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/README.md +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/db/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/db/datasource.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/db/executor.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/export_data/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/export_data/data_download_handler.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/log/access_log_handler.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/model/access_log.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/model/base_model.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/model/parameterized_query.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/model/resource_param_template.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/model/response_result.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/model/user.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/service/access_log_service.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/service/base_service.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/service/resource_param_template_service.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/setup/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/signals.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/static/swagger.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/decorator/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/decorator/sql_injection.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/decorator/swagger.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/dify_utils.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/file/file_exporter.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/file/file_utils.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/fs_util.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/helpers.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/json/NotSortJSONProvider.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/limit/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/limit/limit_util.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/limit/req/rate_limiter_handler.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/limit/req/redis_rate_limiter.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/limit/req_count/count_limiter_handler.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/limit/req_count/redis_count_limiter.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/oss/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/oss/aliyun_oss.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/oss/ks3_oss.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/oss/minio_oss.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/redis/redis_helper.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/request/request.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/swagger/swagger_template.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/swagger/swagger_util.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/task/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/task/task_helper.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/thread/thread_utils.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/wsgi.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask.egg-info/dependency_links.txt +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask.egg-info/requires.txt +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask.egg-info/top_level.txt +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/query_runner/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/query_runner/clickhouse.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/query_runner/elasticsearch.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/query_runner/kingbase.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/query_runner/mysql.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/query_runner/pg.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/settings/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/settings/helpers.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/utils/__init__.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/redash/utils/requests_session.py +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/setup.cfg +0 -0
- {lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: lesscode-flask
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.22
|
|
4
4
|
Summary: lesscode-flask 是基于flask的web开发脚手架项目,该项目初衷为简化开发过程,让研发人员更加关注业务。
|
|
5
5
|
Home-page: https://lesscode-flask
|
|
6
6
|
Author: Chao.yy
|
|
@@ -26,6 +26,16 @@ Requires-Dist: gevent==25.5.1
|
|
|
26
26
|
Requires-Dist: openpyxl==3.1.5
|
|
27
27
|
Requires-Dist: iputil==0.3.1
|
|
28
28
|
Requires-Dist: phone==0.4.5
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: platform
|
|
36
|
+
Dynamic: requires-dist
|
|
37
|
+
Dynamic: requires-python
|
|
38
|
+
Dynamic: summary
|
|
29
39
|
|
|
30
40
|
# lesscode-flask
|
|
31
41
|
|
|
@@ -24,6 +24,8 @@ from lesscode_flask.utils.decorator.sql_injection import contains_sql_injection
|
|
|
24
24
|
from lesscode_flask.utils.helpers import inject_args, generate_uuid, app_config
|
|
25
25
|
from lesscode_flask.utils.json.NotSortJSONProvider import NotSortJSONProvider
|
|
26
26
|
from lesscode_flask.utils.limit import RedisRateLimiter
|
|
27
|
+
from lesscode_flask.utils.limit.consecutive.consecutive_limiter_handler import ConsecutiveAccessLimitHandler
|
|
28
|
+
from lesscode_flask.utils.limit.consecutive.redis_consecutive_limiter import RedisConsecutiveAccessLimiter
|
|
27
29
|
from lesscode_flask.utils.limit.limit_util import get_rate_limit_info, get_count_limit_info, get_user_limit_policy
|
|
28
30
|
from lesscode_flask.utils.limit.req.rate_limiter_handler import RateLimitHandler
|
|
29
31
|
from lesscode_flask.utils.limit.req_count.count_limiter_handler import CountLimitHandler
|
|
@@ -62,10 +64,14 @@ class Lesscoder(Flask):
|
|
|
62
64
|
self.register_error_handler(Exception, self.handle_exception)
|
|
63
65
|
REDIS_RATE_LIMIT_ENABLE = self.config.get("RATE_LIMIT_ENABLE", False)
|
|
64
66
|
if REDIS_RATE_LIMIT_ENABLE:
|
|
65
|
-
self.rateLimiter = RedisRateLimiter(self.config.get("
|
|
67
|
+
self.rateLimiter = RedisRateLimiter(self.config.get("REDIS_LIMIT_KEY", "redis"))
|
|
66
68
|
REDIS_COUNT_LIMIT_ENABLE = self.config.get("COUNT_LIMIT_ENABLE", False)
|
|
67
69
|
if REDIS_COUNT_LIMIT_ENABLE:
|
|
68
|
-
self.countLimiter = RedisCountLimiter(self.config.get("
|
|
70
|
+
self.countLimiter = RedisCountLimiter(self.config.get("REDIS_LIMIT_KEY", "redis"))
|
|
71
|
+
|
|
72
|
+
REDIS_CONSECUTIVE_LIMIT_ENABLE = self.config.get("CONSECUTIVE_ACCESS_LIMIT_ENABLE", False)
|
|
73
|
+
if REDIS_CONSECUTIVE_LIMIT_ENABLE:
|
|
74
|
+
self.consecutiveAccessLimiter = RedisConsecutiveAccessLimiter(self.config.get("REDIS_LIMIT_KEY", "redis"))
|
|
69
75
|
|
|
70
76
|
def preprocess_request(self) -> ft.ResponseReturnValue | None:
|
|
71
77
|
v = super(Lesscoder, self).preprocess_request()
|
|
@@ -86,6 +92,14 @@ class Lesscoder(Flask):
|
|
|
86
92
|
rateLimitHandler = self.config.get("RATE_LIMIT_HANDLER", RateLimitHandler)
|
|
87
93
|
rateLimitHandler(request,delay, excess).response_handler()
|
|
88
94
|
|
|
95
|
+
if hasattr(self, 'consecutiveAccessLimiter') and self.consecutiveAccessLimiter:
|
|
96
|
+
if not user_limit_policy:
|
|
97
|
+
user_limit_policy = get_user_limit_policy()
|
|
98
|
+
# 是否触发限流 延迟时间 超出数量
|
|
99
|
+
allowed,current_count = self.consecutiveAccessLimiter.is_allowed(user_limit_policy)
|
|
100
|
+
if not allowed :
|
|
101
|
+
consecutiveAccessLimiter = self.config.get("CONSECUTIVE_ACCESS_LIMIT_HANDLER", ConsecutiveAccessLimitHandler)
|
|
102
|
+
consecutiveAccessLimiter(request,current_count).response_handler()
|
|
89
103
|
if self.config.get("AUTHORIZATION_ENABLE"): # 启动 AUTHORIZATION_ENABLE 才进行权限验证
|
|
90
104
|
# 获取当前请求的url
|
|
91
105
|
url = request.path
|
|
@@ -17,6 +17,8 @@ class UserLimitPolicy():
|
|
|
17
17
|
count_limit_enable: int = 0,
|
|
18
18
|
count_limit_window_sec: int = 43200,
|
|
19
19
|
count_limit_count: int = 500,
|
|
20
|
+
consecutive_limit_count = 30, # 连续访问次数限制,默认30次
|
|
21
|
+
consecutive_limit_enable = 0, # 连续访问限制是否启用,0-不启用,1-启用
|
|
20
22
|
white_list: Union[str, list] = None,
|
|
21
23
|
alert_webhook_url: str = None,
|
|
22
24
|
):
|
|
@@ -47,7 +49,8 @@ class UserLimitPolicy():
|
|
|
47
49
|
self.count_limit_window_sec = int(count_limit_window_sec) if count_limit_window_sec is not None else 43200
|
|
48
50
|
self.count_limit_count = int(count_limit_count) if count_limit_count is not None else 500
|
|
49
51
|
self.alert_webhook_url = alert_webhook_url
|
|
50
|
-
|
|
52
|
+
self.consecutive_limit_count = int(consecutive_limit_count) if consecutive_limit_count is not None else 20 # 连续访问次数限制,默认20次
|
|
53
|
+
self.consecutive_limit_enable = int(consecutive_limit_enable) if consecutive_limit_enable is not None else 0 # 连续访问限制是否启用,0-不启用,1-启用
|
|
51
54
|
# 修改后的 white_list 处理逻辑
|
|
52
55
|
if isinstance(white_list, str):
|
|
53
56
|
self.white_list = json.loads(white_list) if white_list else []
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
3
|
|
|
4
|
+
from lesscode_flask.utils.limit.consecutive.consecutive_limiter_handler import ConsecutiveAccessLimitHandler
|
|
4
5
|
from lesscode_flask.utils.limit.req.rate_limiter_handler import RateLimitHandler
|
|
5
6
|
from lesscode_flask.utils.limit.req_count.count_limiter_handler import CountLimitHandler
|
|
6
7
|
|
|
@@ -75,10 +76,9 @@ class BaseConfig:
|
|
|
75
76
|
REDIS_CACHE_KEY = "redis"
|
|
76
77
|
# 权限缓存key
|
|
77
78
|
REDIS_OAUTH_KEY = "oauth2_redis"
|
|
78
|
-
#
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
REDIS_COUNT_LIMIT_KEY = "oauth2_redis"
|
|
79
|
+
# 限流缓存key
|
|
80
|
+
REDIS_LIMIT_KEY = "oauth2_redis"
|
|
81
|
+
|
|
82
82
|
##**************权限控制相关*****************##
|
|
83
83
|
# 是否启用权限验证
|
|
84
84
|
AUTHORIZATION_ENABLE: bool = False
|
|
@@ -92,6 +92,7 @@ class BaseConfig:
|
|
|
92
92
|
OAUTH2_REFRESH_TOKEN_GENERATOR = True
|
|
93
93
|
# 是否启用限流频率验证
|
|
94
94
|
RATE_LIMIT_ENABLE: bool = False
|
|
95
|
+
|
|
95
96
|
# 触发限流的处理函数
|
|
96
97
|
RATE_LIMIT_HANDLER = RateLimitHandler
|
|
97
98
|
# # 限流频率窗口 单位是每秒
|
|
@@ -109,6 +110,11 @@ class BaseConfig:
|
|
|
109
110
|
# COUNT_LIMIT_COUNT = 500
|
|
110
111
|
# # 窗口期时长 单位秒
|
|
111
112
|
# COUNT_LIMIT_TIME_WINDOW = 60*60*12
|
|
113
|
+
|
|
114
|
+
# 是否启用连续请求单一接口限流频率验证
|
|
115
|
+
CONSECUTIVE_ACCESS_LIMIT_ENABLE: bool = False
|
|
116
|
+
CONSECUTIVE_ACCESS_LIMIT_HANDLER = ConsecutiveAccessLimitHandler
|
|
117
|
+
|
|
112
118
|
# 白名单
|
|
113
119
|
LIMIT_WHITE_LIST: list = ["/ike2b/user/WXOA/login", "/ike2b/detail/company/node/get_note",
|
|
114
120
|
"/ike2b/user/attention/attention_company_status",
|
|
@@ -55,7 +55,7 @@ def deal_cache(func, ex, cache_key, *args, **params):
|
|
|
55
55
|
end = datetime.datetime.now()
|
|
56
56
|
logging.info("[组件:{}]!用时{}".format(func_name, end - start))
|
|
57
57
|
# 接口时间小于0.6s不计入缓存
|
|
58
|
-
if (end - start).total_seconds()
|
|
58
|
+
if (end - start).total_seconds() >= 0.6:
|
|
59
59
|
# 插入缓存表
|
|
60
60
|
logging.info("写入缓存")
|
|
61
61
|
insert_cache(data, ex, cache_key)
|
|
@@ -0,0 +1,56 @@
|
|
|
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 ConsecutiveAccessLimitHandler:
|
|
15
|
+
"""
|
|
16
|
+
限流后的处理函数实现
|
|
17
|
+
"""
|
|
18
|
+
def __init__(self, req, current_count: int):
|
|
19
|
+
"""
|
|
20
|
+
初始化
|
|
21
|
+
:param req:
|
|
22
|
+
:param current_count: 当前连续访问次数
|
|
23
|
+
"""
|
|
24
|
+
self.req = req
|
|
25
|
+
self.current_count = current_count
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def response_handler(self):
|
|
29
|
+
# 如果配置了飞书 webhook URL,则发送告警通知
|
|
30
|
+
limit_fs_webhook_url = current_app.config.get("LIMIT_FS_WEBHOOK_URL")
|
|
31
|
+
# 如果配置了飞书 webhook URL,则发送告警通知
|
|
32
|
+
if limit_fs_webhook_url:
|
|
33
|
+
content = []
|
|
34
|
+
current_user = flask_login.current_user
|
|
35
|
+
# 收集用户相关信息
|
|
36
|
+
content.append({"tag": "text","text": f"用户名称:{current_user.display_name}\n"})
|
|
37
|
+
phone_no = current_user.phone_no if current_user.phone_no is not None else "-"
|
|
38
|
+
content.append({"tag": "text","text": f"手机号:{phone_no}\n"})
|
|
39
|
+
content.append({"tag": "text","text": f"用户IP:{request.remote_addr}\n"})
|
|
40
|
+
content.append({"tag": "text","text": f"资源地址:{request.url_rule.rule}\n"})
|
|
41
|
+
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
|
42
|
+
if token:
|
|
43
|
+
FS_OAM_SERVICE_URL = current_app.config.get("FS_OAM_SERVICE_URL")
|
|
44
|
+
content.append({"tag": "text","text": f"运维处理:\n"})
|
|
45
|
+
lock_account_url = f"{FS_OAM_SERVICE_URL}/icp/authUser/lock_account?id={current_user.id}"
|
|
46
|
+
url = f"{FS_OAM_SERVICE_URL}/icp/oauth/logout_token?token={token}"
|
|
47
|
+
content.append({"tag": "a","text": "强制下线","href": f"{url}"})
|
|
48
|
+
content.append({"tag": "a", "text": " 禁止登录 ", "href": f"{lock_account_url}"})
|
|
49
|
+
ban_ip_url = f"{FS_OAM_SERVICE_URL}/icp/accessLog/ban_ip?ip={request.remote_addr}"
|
|
50
|
+
content.append({"tag": "a", "text": "封禁IP ", "href": f"{ban_ip_url}"})
|
|
51
|
+
|
|
52
|
+
# 发送飞书 webhook 告警
|
|
53
|
+
fs_webhook(limit_fs_webhook_url, "触发连续请求单一接口限流告警", content)
|
|
54
|
+
return ResponseResult.fail(status_code="403", http_code="403", message="请求过于频繁,请稍后再试!")
|
|
55
|
+
|
|
56
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from flask import request
|
|
3
|
+
|
|
4
|
+
from lesscode_flask.model.user import flask_login
|
|
5
|
+
from lesscode_flask.model.user_limit_policy import UserLimitPolicy
|
|
6
|
+
from lesscode_flask.utils.redis.redis_helper import RedisHelper
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
class RedisConsecutiveAccessLimiter:
|
|
11
|
+
"""Redis连续访问限流器实现"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, redis_key):
|
|
14
|
+
self.redis_key = redis_key
|
|
15
|
+
|
|
16
|
+
def is_allowed(self, user_limit_policy: UserLimitPolicy):
|
|
17
|
+
"""
|
|
18
|
+
检查是否允许请求(限制用户连续访问同一路径)
|
|
19
|
+
:return: (allowed, current_count)
|
|
20
|
+
"""
|
|
21
|
+
consecutive_limit_count = getattr(user_limit_policy, 'consecutive_limit_count', 20)
|
|
22
|
+
consecutive_limit_enable = getattr(user_limit_policy, 'consecutive_limit_enable', 0)
|
|
23
|
+
limit_white_list = getattr(user_limit_policy, 'white_list', [])
|
|
24
|
+
|
|
25
|
+
request_url = request.url_rule.rule if request.url_rule else ""
|
|
26
|
+
|
|
27
|
+
# 未启用连续访问限制 或者 在白名单中 直接返回允许
|
|
28
|
+
if consecutive_limit_enable == 0 or request_url in limit_white_list:
|
|
29
|
+
return True, 0
|
|
30
|
+
|
|
31
|
+
# 限流键 (包含用户标识和请求路径)
|
|
32
|
+
limit_key = None
|
|
33
|
+
# 1、获取当前用户
|
|
34
|
+
current_user = flask_login.current_user
|
|
35
|
+
if current_user and not current_user.is_anonymous_user:
|
|
36
|
+
# 拼接 key 用户id
|
|
37
|
+
limit_key = current_user.id
|
|
38
|
+
# 如果键为空,使用客户端IP
|
|
39
|
+
if not limit_key:
|
|
40
|
+
limit_key = f"{request.remote_addr}"
|
|
41
|
+
limit_key = f"{limit_key}"
|
|
42
|
+
key = f"limit_consecutive:{limit_key}:{request_url}"
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
# 获取当前连续访问次数
|
|
46
|
+
current_count_str = RedisHelper(self.redis_key).sync_get(key)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if current_count_str is None:
|
|
50
|
+
keys = RedisHelper(self.redis_key).sync_keys(f"limit_consecutive:{limit_key}:*")
|
|
51
|
+
RedisHelper(self.redis_key).sync_delete(keys)
|
|
52
|
+
|
|
53
|
+
# 第一次访问,设置计数为1
|
|
54
|
+
current_count = 1
|
|
55
|
+
RedisHelper(self.redis_key).sync_set(key, current_count, 3600) # 默认保存1小时
|
|
56
|
+
else:
|
|
57
|
+
# current_count = int(current_count_str) + 1
|
|
58
|
+
# 增加连续访问计数
|
|
59
|
+
current_count = RedisHelper(self.redis_key).sync_incrby(name=key, amount=1)
|
|
60
|
+
|
|
61
|
+
# 检查是否超过限制
|
|
62
|
+
if current_count >= consecutive_limit_count:
|
|
63
|
+
# 超过限制
|
|
64
|
+
return False, current_count
|
|
65
|
+
else:
|
|
66
|
+
return True, current_count
|
|
67
|
+
|
|
68
|
+
except Exception as e:
|
|
69
|
+
# Redis出错时的降级处理
|
|
70
|
+
logger.error(f"Redis consecutive access limiter error: {e}")
|
|
71
|
+
return True, 0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: lesscode-flask
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.22
|
|
4
4
|
Summary: lesscode-flask 是基于flask的web开发脚手架项目,该项目初衷为简化开发过程,让研发人员更加关注业务。
|
|
5
5
|
Home-page: https://lesscode-flask
|
|
6
6
|
Author: Chao.yy
|
|
@@ -26,6 +26,16 @@ Requires-Dist: gevent==25.5.1
|
|
|
26
26
|
Requires-Dist: openpyxl==3.1.5
|
|
27
27
|
Requires-Dist: iputil==0.3.1
|
|
28
28
|
Requires-Dist: phone==0.4.5
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: platform
|
|
36
|
+
Dynamic: requires-dist
|
|
37
|
+
Dynamic: requires-python
|
|
38
|
+
Dynamic: summary
|
|
29
39
|
|
|
30
40
|
# lesscode-flask
|
|
31
41
|
|
|
@@ -40,6 +40,8 @@ lesscode_flask/utils/file/file_utils.py
|
|
|
40
40
|
lesscode_flask/utils/json/NotSortJSONProvider.py
|
|
41
41
|
lesscode_flask/utils/limit/__init__.py
|
|
42
42
|
lesscode_flask/utils/limit/limit_util.py
|
|
43
|
+
lesscode_flask/utils/limit/consecutive/consecutive_limiter_handler.py
|
|
44
|
+
lesscode_flask/utils/limit/consecutive/redis_consecutive_limiter.py
|
|
43
45
|
lesscode_flask/utils/limit/req/rate_limiter_handler.py
|
|
44
46
|
lesscode_flask/utils/limit/req/redis_rate_limiter.py
|
|
45
47
|
lesscode_flask/utils/limit/req_count/count_limiter_handler.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/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.20 → lesscode_flask-0.2.22}/lesscode_flask/model/resource_param_template.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/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
|
{lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/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.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/json/NotSortJSONProvider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/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
|
|
File without changes
|
{lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/swagger/swagger_template.py
RENAMED
|
File without changes
|
{lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/lesscode_flask/utils/swagger/swagger_util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode-flask-0.2.20 → lesscode_flask-0.2.22}/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
|