sa-token-python-core 0.1.4__py3-none-any.whl → 0.1.5__py3-none-any.whl

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.
sa_token/config.py CHANGED
@@ -105,13 +105,7 @@ class SaTokenConfig:
105
105
  jwt_algorithm: str = "HS256"
106
106
 
107
107
  is_print_banner: bool = True
108
- """是否打印启动横幅。默认 True,与 Java / Go 版一致。
109
-
110
- 原生 ``build()``、FastAPI / Starlette 服务启动、Flask ``init_app``、
111
- Django 中间件加载时都会尝试打印,同一进程只输出一次。
112
- 关闭:``SaToken.builder().print_banner(False)`` 或
113
- ``set_option(is_print_banner=False)``。
114
- """
108
+ """初始化时是否打印启动横幅。"""
115
109
 
116
110
  extra: dict[str, Any] = field(default_factory=dict)
117
111
  """给扩展模块(OAuth2 / SSO / 在线用户)放自定义配置。"""
@@ -14,7 +14,6 @@ from typing import Any, TypeVar
14
14
  from ..adapter.http import HttpContext
15
15
  from ..adapter.path import PathAuthConfig
16
16
  from ..adapter.pipeline import build_rule, resolve_token, run_auth_flow, run_path_auth
17
- from ..banner import emit_configured_banner
18
17
  from ..exception import SaTokenException
19
18
  from ..permission import MatchMode
20
19
  from ..stp_util import get_manager
@@ -79,7 +78,6 @@ class SaTokenDjangoMiddleware:
79
78
 
80
79
  def __init__(self, get_response: Callable[[Any], Any]) -> None:
81
80
  self._get_response = get_response
82
- emit_configured_banner()
83
81
 
84
82
  def __call__(self, request: Any) -> Any:
85
83
  ctx = DjangoHttpContext(request)
@@ -13,7 +13,6 @@ from typing import TYPE_CHECKING, Any, TypeVar
13
13
  from ..adapter.http import HttpContext
14
14
  from ..adapter.path import PathAuthConfig
15
15
  from ..adapter.pipeline import build_rule, resolve_token, run_auth_flow, run_path_auth
16
- from ..banner import emit_configured_banner
17
16
  from ..exception import SaTokenException
18
17
  from ..permission import MatchMode
19
18
  from ..stp_util import get_manager
@@ -78,9 +77,6 @@ class SaTokenFlask:
78
77
  def init_app(self, app: Flask) -> None:
79
78
  app.before_request(self._before_request)
80
79
  app.register_error_handler(SaTokenException, self._handle_exception)
81
- if hasattr(app, "before_serving"):
82
- app.before_serving(emit_configured_banner)
83
- emit_configured_banner()
84
80
 
85
81
  # 请求钩子 --------------------------------------------------------------
86
82
 
@@ -26,7 +26,6 @@ except ImportError as exc: # pragma: no cover - 依赖缺失路径
26
26
  from ..adapter.http import HttpContext
27
27
  from ..adapter.path import PathAuthConfig
28
28
  from ..adapter.pipeline import build_rule, resolve_token, run_auth_flow, run_path_auth
29
- from ..banner import emit_configured_banner
30
29
  from ..exception import SaTokenException
31
30
  from ..permission import MatchMode
32
31
  from ..stp_util import get_manager
@@ -100,7 +99,6 @@ class SaTokenMiddleware(BaseHTTPMiddleware):
100
99
  super().__init__(app)
101
100
  self.path_auth = path_auth
102
101
  self.login_type = login_type
103
- emit_configured_banner()
104
102
 
105
103
  async def dispatch(
106
104
  self,
sa_token/manager.py CHANGED
@@ -6,9 +6,9 @@ Manager 负责组装:配置 + 存储 + Token 策略 + 事件总线 + 权限数
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import sys
9
10
  from typing import TYPE_CHECKING, Any
10
11
 
11
- from .banner import emit_banner, write_banner
12
12
  from .config import SaTokenConfig
13
13
  from .listener import Event, EventBus, Listener
14
14
  from .model import DEFAULT_LOGIN_TYPE
@@ -22,7 +22,15 @@ if TYPE_CHECKING: # pragma: no cover - 仅供类型检查
22
22
 
23
23
  __all__ = ["SaTokenManager", "SaTokenBuilder", "SaToken", "__version__"]
24
24
 
25
- __version__ = "0.1.4"
25
+ __version__ = "0.1.5"
26
+
27
+ _BANNER = r"""
28
+ _____ ______ __
29
+ / ___/____ _ /_ __/___ / /_____ ____
30
+ \__ \/ __ `/ / / / __ \/ //_/ _ \/ __ \
31
+ ___/ / /_/ / / / / /_/ / ,< / __/ / / /
32
+ /____/\__,_/ /_/ \____/_/|_|\___/_/ /_/
33
+ """
26
34
 
27
35
 
28
36
  class SaTokenManager:
@@ -46,7 +54,6 @@ class SaTokenManager:
46
54
  self._nonce_manager: NonceManager | None = None
47
55
  self._refresh_token_manager: RefreshTokenManager | None = None
48
56
  self._temp_token_manager: TempTokenManager | None = None
49
- emit_banner(self)
50
57
 
51
58
  def stp(self, login_type: str = DEFAULT_LOGIN_TYPE) -> StpLogic:
52
59
  """取得指定账号体系的逻辑实例,不同 ``login_type`` 之间存储完全隔离。"""
@@ -93,8 +100,16 @@ class SaTokenManager:
93
100
  return self._temp_token_manager
94
101
 
95
102
  def print_banner(self) -> None:
96
- """手动打印启动横幅,不受「只打印一次」限制。"""
97
- write_banner(self)
103
+ lines = [
104
+ _BANNER,
105
+ f":: sa-token-python :: (v{__version__})",
106
+ f":: Python :: {sys.version.split()[0]}",
107
+ f":: Token Style :: {self.config.token_style}",
108
+ f":: Token Timeout :: {self.config.timeout} 秒",
109
+ f":: Storage :: {type(self.storage).__name__}",
110
+ "",
111
+ ]
112
+ print("\n".join(lines))
98
113
 
99
114
 
100
115
  class SaTokenBuilder:
@@ -175,7 +190,6 @@ class SaTokenBuilder:
175
190
  return self
176
191
 
177
192
  def print_banner(self, value: bool) -> SaTokenBuilder:
178
- """是否打印启动横幅,默认 True。传入 False 关闭。"""
179
193
  self._config.is_print_banner = value
180
194
  return self
181
195
 
@@ -213,6 +227,8 @@ class SaTokenBuilder:
213
227
  stp_interface=self._stp_interface,
214
228
  events=self._events,
215
229
  )
230
+ if self._config.is_print_banner:
231
+ manager.print_banner()
216
232
  if self._set_global:
217
233
  from .stp_util import set_manager
218
234
 
sa_token/stp_util.py CHANGED
@@ -29,9 +29,6 @@ def set_manager(manager: SaTokenManager) -> None:
29
29
  """设置全局 Manager,一般由 ``SaTokenBuilder.build()`` 自动调用。"""
30
30
  global _manager
31
31
  _manager = manager
32
- from .banner import emit_banner
33
-
34
- emit_banner(manager)
35
32
 
36
33
 
37
34
  def get_manager() -> SaTokenManager:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sa-token-python-core
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: 有状态 Token 认证与权限鉴权框架(轻量核心)。灵感来源于 Java 的 Sa-Token。常用依赖请安装 sa-token-python;Web 框架按 extras 安装。
5
5
  Project-URL: Homepage, https://github.com/Star-yb/sa-token-python
6
6
  Project-URL: Documentation, https://github.com/Star-yb/sa-token-python
@@ -313,7 +313,6 @@ SaToken.builder() \
313
313
  | `is_write_cookie` | `False` | FastAPI 显式调用写 Cookie 助手时是否生效 |
314
314
  | `storage_key_prefix` | `satoken:` | 所有存储键前缀 |
315
315
  | `jwt_secret_key` | `None` | JWT 风格时必填 |
316
- | `is_print_banner` | `True` | 启动时打印 Sa-Token 标志,`.print_banner(False)` 关闭 |
317
316
 
318
317
  Token 读取顺序全局唯一:**Header → Authorization 兜底 → Cookie → Query**。各框架禁止自己再解析一遍。
319
318
 
@@ -505,8 +504,8 @@ class MyappConfig(AppConfig):
505
504
  from sa_token import SaToken
506
505
  from sa_token.storage import MemoryStorage, RedisStorage
507
506
 
508
- SaToken.builder().storage(MemoryStorage()).timeout(86400).build()
509
- SaToken.builder().storage(RedisStorage.from_url("redis://127.0.0.1:6379/0")).timeout(86400).build()
507
+ SaToken.builder().storage(MemoryStorage()).timeout(86400).print_banner(False).build()
508
+ SaToken.builder().storage(RedisStorage.from_url("redis://127.0.0.1:6379/0")).timeout(86400).print_banner(False).build()
510
509
  ```
511
510
 
512
511
  ### 2. 注册中间件
@@ -1,17 +1,16 @@
1
1
  sa_token/__init__.py,sha256=pv7sfIXDmQMmRJuNRuXDb_q_bjVFnUrDw1kxk7gkhms,2165
2
- sa_token/banner.py,sha256=vNNoPd2Q9ynT3FJvxOifAWFUI9f8QmCyOw5MTuzsCzE,2240
3
- sa_token/config.py,sha256=vwwhUzLCMuw8RP9NPsalWy9HAGtR4VGsUhLCvCvlrWk,4841
2
+ sa_token/config.py,sha256=CkRuH7mtBlnyp9DrbVZvbt1ESBjWbBKJndIjH2hbG6I,4540
4
3
  sa_token/context.py,sha256=cwI320c07fhHFkNawlhjOLQbhMkWm5jeb69vD3qVxuw,2002
5
4
  sa_token/exception.py,sha256=4KOgvZOx6nRuLB482Ehm5l841SWxRsiw_T-mbkR6Z14,3997
6
5
  sa_token/listener.py,sha256=pNLry8yllu35fTw9CnjmgaYLHuI8iyzS_d7NhXxoWm8,3129
7
- sa_token/manager.py,sha256=XZkZJergXRs63r7VzzbxI9BfyOggmQ-ys3nvOh8kZ-0,7808
6
+ sa_token/manager.py,sha256=OM3Q_eMrVSv0KT2BHqg2pDCT0vvADXuyTt9KWtRX6cY,8287
8
7
  sa_token/model.py,sha256=2Twvy2XXkTBuab1Mg4SSQfXRDXSIKaQ6xnu8NUtMN0w,4374
9
8
  sa_token/permission.py,sha256=B_KKGaANfPtFSdGlNrp0bk2s_ZVbeHkYvLzoOlwQvkk,2487
10
9
  sa_token/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
10
  sa_token/session.py,sha256=9DkqLcPxppiqbVVwf2ybjSDv--4okWs__cPYbfsWGW0,2696
12
11
  sa_token/stp_interface.py,sha256=dxjPRj5jvuLLiGgh-o0EXhqouL42q59xob6e5IWhCBE,616
13
12
  sa_token/stp_logic.py,sha256=VvJG6wEZkTbpCW-Dm4SQkXmJ69tkU2ihyxRmUrBYWSc,35826
14
- sa_token/stp_util.py,sha256=LRP_2csZybI-YxnuqQY-iCUDROwy51PtP9pV2hIu_RI,12747
13
+ sa_token/stp_util.py,sha256=3G2jkDAulUsymQWxwf3AjrfcgUClt7oQmz8bNQ0iwgo,12685
15
14
  sa_token/sync.py,sha256=8ac7w2k0ER58jblXXV2ZaKk30qBiuwooPjniTjvWcjg,8890
16
15
  sa_token/token_io.py,sha256=rWqKJMGVZ-DCu0kjLMMZoaq2pR-rJql-96qkfyjkHuw,2174
17
16
  sa_token/adapter/__init__.py,sha256=NamL0PvdUaLMJgEs1Yo9MXeVkmFRUudhw9FtlELyEOc,638
@@ -19,11 +18,11 @@ sa_token/adapter/http.py,sha256=1pOdrT-1RcurejFYHj4MoNCD4Yr6UjcBiV5JdVeOwAc,1998
19
18
  sa_token/adapter/path.py,sha256=ZJpfY7SKVkDb5Pz9bdlUwsiJHyfP5FswIe80qbtApsU,5231
20
19
  sa_token/adapter/pipeline.py,sha256=0Eq_W6pOM4D6yV3LMomeA-XnrGB-GXSzbzn9k-7tyGI,2837
21
20
  sa_token/integration/__init__.py,sha256=lc4Bi1kdQnsN3McdcNPHptuOg8MY5InYCL7ZkugJk7I,380
22
- sa_token/integration/django.py,sha256=IWqq7ytKytj3mC_waMe0ww1fgXatyKZh4NwLeL4FeMs,4255
21
+ sa_token/integration/django.py,sha256=7E0ibwfGK9pt_fHTxnVQk5TcFNqNCtl339HQJhDF_PE,4178
23
22
  sa_token/integration/fastapi.py,sha256=oHNC_ErZikkbRWDXcBnWvR2gL9vZlNIKHcyUbG2FAyQ,9988
24
23
  sa_token/integration/fastapi_oauth2.py,sha256=2pZPgYtZiYBS7Wne7VRqlcGfjEz5jm882xBlOYIXgH8,5109
25
- sa_token/integration/flask.py,sha256=rFkFvms5wvJWm0KsrFl8upCtUPxKJQCucxeMU7dNvdg,6526
26
- sa_token/integration/starlette.py,sha256=bMZk2a6yBqqhayUSv9XcTuJ8SXp78oO5b0OgOt3nmBs,7541
24
+ sa_token/integration/flask.py,sha256=_PxsKbyTCqm22uy1EOSIhoKPlGvbY5SpN0l2JCazKZw,6351
25
+ sa_token/integration/starlette.py,sha256=XIcKDhsIcjmjDDrUYegwhDYBZiK5LA5vjaP8XJ7akFA,7464
27
26
  sa_token/oauth2/__init__.py,sha256=J4tV401Y7hcLiyKUhypxrOoaZwgx-jMV_tee1QwyCsM,487
28
27
  sa_token/oauth2/model.py,sha256=OWQCiNWKro4elFwgEeFz7iviW7IqHD4Dhw7OQ32rvi8,3764
29
28
  sa_token/oauth2/server.py,sha256=NSzjwFU1ukO1jK-gUAdxkJZTID4-rUO0p7ZzAL_AY6Q,13884
@@ -41,7 +40,7 @@ sa_token/strategy/__init__.py,sha256=j3DzIIMPqHF3L6_6VxxQAHtwEH9AX7GPv1ON-dyp67c
41
40
  sa_token/strategy/base.py,sha256=lNGwe-cW7gEnE6xn7_9gsCSkT4u-Ty5SZElqsoUMpck,634
42
41
  sa_token/strategy/builtin.py,sha256=2tYH32UXMbUu-Uup_yMouNSYNjO6XMXPNpnjZOGNMC0,2722
43
42
  sa_token/strategy/jwt.py,sha256=qZo2DoBG4Cq_tz5swtgasYiQACARzk-_ri-nO9_kWq8,2360
44
- sa_token_python_core-0.1.4.dist-info/METADATA,sha256=k5dSP9KU6tzgLZjAcDtt2X9hp5WXmZ3sVj-kfuUULu4,26854
45
- sa_token_python_core-0.1.4.dist-info/WHEEL,sha256=THafob7ofN-NsuMN7Mg4qZyHaQI7KkD-QlcQatYhXPo,87
46
- sa_token_python_core-0.1.4.dist-info/licenses/LICENSE,sha256=KglpXsmvkzfIiEB2FvZnD5SuCyEtV1px4b4nTzQFHG8,10860
47
- sa_token_python_core-0.1.4.dist-info/RECORD,,
43
+ sa_token_python_core-0.1.5.dist-info/METADATA,sha256=Wem7sRdbAG9j300Ni7tX0tJz5onEzWxCcUk5b5giQQ4,26797
44
+ sa_token_python_core-0.1.5.dist-info/WHEEL,sha256=THafob7ofN-NsuMN7Mg4qZyHaQI7KkD-QlcQatYhXPo,87
45
+ sa_token_python_core-0.1.5.dist-info/licenses/LICENSE,sha256=KglpXsmvkzfIiEB2FvZnD5SuCyEtV1px4b4nTzQFHG8,10860
46
+ sa_token_python_core-0.1.5.dist-info/RECORD,,
sa_token/banner.py DELETED
@@ -1,76 +0,0 @@
1
- """启动横幅。
2
-
3
- 与 Java / Go 版一致:初始化时默认打印一次 ASCII 标志。
4
- Web 框架适配会在服务启动时再尝试打印;进程内只输出一次。
5
- ``is_print_banner=False`` 或 ``.print_banner(False)`` 可关闭。
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- import sys
11
- from typing import TYPE_CHECKING
12
-
13
- if TYPE_CHECKING: # pragma: no cover - 仅供类型检查
14
- from .manager import SaTokenManager
15
-
16
- __all__ = ["BANNER", "emit_banner", "emit_configured_banner", "reset_banner_state"]
17
-
18
- BANNER = r"""
19
- _____ ______ __
20
- / ___/____ _ /_ __/___ / /_____ ____
21
- \__ \/ __ `/ / / / __ \/ //_/ _ \/ __ \
22
- ___/ / /_/ / / / / /_/ / ,< / __/ / / /
23
- /____/\__,_/ /_/ \____/_/|_|\___/_/ /_/
24
- """
25
-
26
- _printed = False
27
-
28
-
29
- def reset_banner_state() -> None:
30
- """测试隔离:允许下一个用例再次打印。"""
31
- global _printed
32
- _printed = False
33
-
34
-
35
- def render_banner(manager: SaTokenManager) -> str:
36
- from .manager import __version__
37
-
38
- timeout = manager.config.timeout
39
- timeout_text = "永久" if timeout < 0 else f"{timeout} 秒"
40
- lines = [
41
- BANNER.rstrip("\n"),
42
- f":: sa-token-python :: (v{__version__})",
43
- f":: Python :: {sys.version.split()[0]}",
44
- f":: Token Style :: {manager.config.token_style}",
45
- f":: Token Timeout :: {timeout_text}",
46
- f":: Storage :: {type(manager.storage).__name__}",
47
- "",
48
- ]
49
- return "\n".join(lines)
50
-
51
-
52
- def write_banner(manager: SaTokenManager) -> None:
53
- """无条件写出横幅,供手动调用。"""
54
- sys.stdout.write(render_banner(manager) + "\n")
55
- sys.stdout.flush()
56
-
57
-
58
- def emit_banner(manager: SaTokenManager) -> None:
59
- """按配置打印横幅,同一进程只打印一次。"""
60
- global _printed
61
- if _printed or not manager.config.is_print_banner:
62
- return
63
- _printed = True
64
- write_banner(manager)
65
-
66
-
67
- def emit_configured_banner() -> None:
68
- """框架启动钩子:全局 Manager 已就绪则打印。"""
69
- from .exception import SaTokenNotInitializedException
70
- from .stp_util import get_manager
71
-
72
- try:
73
- manager = get_manager()
74
- except SaTokenNotInitializedException:
75
- return
76
- emit_banner(manager)