sa-token-python-core 0.1.4__tar.gz → 0.1.5__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.
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/PKG-INFO +3 -4
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/README.md +2 -3
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/examples/native/quick_start.py +1 -1
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/pyproject.toml +1 -1
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/config.py +1 -7
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/django.py +0 -2
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/flask.py +0 -4
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/starlette.py +0 -2
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/manager.py +22 -6
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/stp_util.py +0 -3
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/conftest.py +0 -9
- sa_token_python_core-0.1.4/src/sa_token/banner.py +0 -76
- sa_token_python_core-0.1.4/tests/test_banner.py +0 -106
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/.github/workflows/ci.yml +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/.gitignore +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/LICENSE +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/examples/fastapi/main.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/examples/flask/main.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/__init__.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/adapter/__init__.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/adapter/http.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/adapter/path.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/adapter/pipeline.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/context.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/exception.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/__init__.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/fastapi.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/fastapi_oauth2.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/listener.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/model.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/oauth2/__init__.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/oauth2/model.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/oauth2/server.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/online/__init__.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/permission.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/py.typed +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/security/__init__.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/security/nonce.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/security/refresh.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/security/temp_token.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/session.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/sso/__init__.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/storage/__init__.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/storage/base.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/storage/memory.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/storage/redis.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/stp_interface.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/stp_logic.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/strategy/__init__.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/strategy/base.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/strategy/builtin.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/strategy/jwt.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/sync.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/token_io.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_adapter.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_auth.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_authorization.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_core_isolation.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_extensions.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_integration_fastapi.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_integration_fastapi_oauth2.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_integration_flask.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_optional_backends.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_permission.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_security.py +0 -0
- {sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_storage_and_token.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sa-token-python-core
|
|
3
|
-
Version: 0.1.
|
|
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. 注册中间件
|
|
@@ -263,7 +263,6 @@ SaToken.builder() \
|
|
|
263
263
|
| `is_write_cookie` | `False` | FastAPI 显式调用写 Cookie 助手时是否生效 |
|
|
264
264
|
| `storage_key_prefix` | `satoken:` | 所有存储键前缀 |
|
|
265
265
|
| `jwt_secret_key` | `None` | JWT 风格时必填 |
|
|
266
|
-
| `is_print_banner` | `True` | 启动时打印 Sa-Token 标志,`.print_banner(False)` 关闭 |
|
|
267
266
|
|
|
268
267
|
Token 读取顺序全局唯一:**Header → Authorization 兜底 → Cookie → Query**。各框架禁止自己再解析一遍。
|
|
269
268
|
|
|
@@ -455,8 +454,8 @@ class MyappConfig(AppConfig):
|
|
|
455
454
|
from sa_token import SaToken
|
|
456
455
|
from sa_token.storage import MemoryStorage, RedisStorage
|
|
457
456
|
|
|
458
|
-
SaToken.builder().storage(MemoryStorage()).timeout(86400).build()
|
|
459
|
-
SaToken.builder().storage(RedisStorage.from_url("redis://127.0.0.1:6379/0")).timeout(86400).build()
|
|
457
|
+
SaToken.builder().storage(MemoryStorage()).timeout(86400).print_banner(False).build()
|
|
458
|
+
SaToken.builder().storage(RedisStorage.from_url("redis://127.0.0.1:6379/0")).timeout(86400).print_banner(False).build()
|
|
460
459
|
```
|
|
461
460
|
|
|
462
461
|
### 2. 注册中间件
|
|
@@ -24,7 +24,7 @@ def on_auth_event(data: EventData) -> None:
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
async def main() -> None:
|
|
27
|
-
SaToken.builder().storage(MemoryStorage()).timeout(7200).on(
|
|
27
|
+
SaToken.builder().storage(MemoryStorage()).timeout(7200).print_banner(False).on(
|
|
28
28
|
Event.ALL, on_auth_event
|
|
29
29
|
).build()
|
|
30
30
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sa-token-python-core"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.5"
|
|
8
8
|
description = "有状态 Token 认证与权限鉴权框架(轻量核心)。灵感来源于 Java 的 Sa-Token。常用依赖请安装 sa-token-python;Web 框架按 extras 安装。"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -105,13 +105,7 @@ class SaTokenConfig:
|
|
|
105
105
|
jwt_algorithm: str = "HS256"
|
|
106
106
|
|
|
107
107
|
is_print_banner: bool = True
|
|
108
|
-
"""
|
|
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 / 在线用户)放自定义配置。"""
|
{sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/django.py
RENAMED
|
@@ -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
|
|
{sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/starlette.py
RENAMED
|
@@ -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,
|
|
@@ -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.
|
|
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
|
-
|
|
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
|
|
|
@@ -3,18 +3,10 @@ from __future__ import annotations
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
5
|
from sa_token import SaToken, SaTokenManager
|
|
6
|
-
from sa_token.banner import reset_banner_state
|
|
7
6
|
from sa_token.storage import MemoryStorage
|
|
8
7
|
from sa_token.stp_util import clear_manager
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
@pytest.fixture(autouse=True)
|
|
12
|
-
def _isolate_banner():
|
|
13
|
-
reset_banner_state()
|
|
14
|
-
yield
|
|
15
|
-
reset_banner_state()
|
|
16
|
-
|
|
17
|
-
|
|
18
10
|
@pytest.fixture
|
|
19
11
|
def build_manager():
|
|
20
12
|
"""返回一个构建 Manager 的工厂,测试之间互不干扰。"""
|
|
@@ -30,7 +22,6 @@ def build_manager():
|
|
|
30
22
|
|
|
31
23
|
yield _build
|
|
32
24
|
clear_manager()
|
|
33
|
-
reset_banner_state()
|
|
34
25
|
|
|
35
26
|
|
|
36
27
|
@pytest.fixture
|
|
@@ -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)
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"""启动横幅:默认打印一次,可通过配置关闭。"""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import pytest
|
|
6
|
-
|
|
7
|
-
from sa_token import SaToken, SaTokenConfig, SaTokenManager, __version__, set_manager
|
|
8
|
-
from sa_token.banner import emit_configured_banner, reset_banner_state
|
|
9
|
-
from sa_token.storage import MemoryStorage
|
|
10
|
-
from sa_token.stp_util import clear_manager
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def test_build_prints_banner_by_default(capsys) -> None:
|
|
14
|
-
SaToken.builder().storage(MemoryStorage()).as_global(False).build()
|
|
15
|
-
|
|
16
|
-
output = capsys.readouterr().out
|
|
17
|
-
assert "sa-token-python" in output
|
|
18
|
-
assert f"(v{__version__})" in output
|
|
19
|
-
assert "MemoryStorage" in output
|
|
20
|
-
assert r"/ ___/____ _" in output
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def test_print_banner_false_silences_output(capsys) -> None:
|
|
24
|
-
SaToken.builder().storage(MemoryStorage()).print_banner(False).as_global(False).build()
|
|
25
|
-
|
|
26
|
-
assert capsys.readouterr().out == ""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def test_set_option_can_disable_banner(capsys) -> None:
|
|
30
|
-
SaToken.builder().storage(MemoryStorage()).set_option(is_print_banner=False).as_global(
|
|
31
|
-
False
|
|
32
|
-
).build()
|
|
33
|
-
|
|
34
|
-
assert capsys.readouterr().out == ""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def test_banner_prints_only_once(capsys) -> None:
|
|
38
|
-
manager = SaToken.builder().storage(MemoryStorage()).as_global(False).build()
|
|
39
|
-
capsys.readouterr()
|
|
40
|
-
|
|
41
|
-
manager.print_banner()
|
|
42
|
-
assert "sa-token-python" in capsys.readouterr().out
|
|
43
|
-
|
|
44
|
-
set_manager(manager)
|
|
45
|
-
emit_configured_banner()
|
|
46
|
-
assert capsys.readouterr().out == ""
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def test_direct_manager_construction_prints(capsys) -> None:
|
|
50
|
-
SaTokenManager(SaTokenConfig(), MemoryStorage())
|
|
51
|
-
|
|
52
|
-
output = capsys.readouterr().out
|
|
53
|
-
assert "sa-token-python" in output
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def test_emit_configured_banner_without_manager_is_silent(capsys) -> None:
|
|
57
|
-
clear_manager()
|
|
58
|
-
emit_configured_banner()
|
|
59
|
-
assert capsys.readouterr().out == ""
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def test_reset_allows_reprint(capsys) -> None:
|
|
63
|
-
SaToken.builder().storage(MemoryStorage()).as_global(False).build()
|
|
64
|
-
assert "sa-token-python" in capsys.readouterr().out
|
|
65
|
-
|
|
66
|
-
reset_banner_state()
|
|
67
|
-
SaToken.builder().storage(MemoryStorage()).as_global(False).build()
|
|
68
|
-
assert "sa-token-python" in capsys.readouterr().out
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def test_fastapi_startup_prints_banner(capsys) -> None:
|
|
72
|
-
pytest.importorskip("fastapi")
|
|
73
|
-
from fastapi import FastAPI
|
|
74
|
-
from fastapi.testclient import TestClient
|
|
75
|
-
|
|
76
|
-
from sa_token.integration.fastapi import SaTokenMiddleware
|
|
77
|
-
|
|
78
|
-
manager = SaToken.builder().storage(MemoryStorage()).print_banner(False).build()
|
|
79
|
-
manager.config.is_print_banner = True
|
|
80
|
-
reset_banner_state()
|
|
81
|
-
|
|
82
|
-
app = FastAPI()
|
|
83
|
-
app.add_middleware(SaTokenMiddleware)
|
|
84
|
-
with TestClient(app):
|
|
85
|
-
pass
|
|
86
|
-
|
|
87
|
-
output = capsys.readouterr().out
|
|
88
|
-
assert "sa-token-python" in output
|
|
89
|
-
assert "MemoryStorage" in output
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def test_flask_init_prints_banner(capsys) -> None:
|
|
93
|
-
pytest.importorskip("flask")
|
|
94
|
-
from flask import Flask
|
|
95
|
-
|
|
96
|
-
from sa_token.integration.flask import SaTokenFlask
|
|
97
|
-
|
|
98
|
-
SaToken.builder().storage(MemoryStorage()).build()
|
|
99
|
-
capsys.readouterr()
|
|
100
|
-
reset_banner_state()
|
|
101
|
-
|
|
102
|
-
app = Flask(__name__)
|
|
103
|
-
SaTokenFlask(app)
|
|
104
|
-
|
|
105
|
-
output = capsys.readouterr().out
|
|
106
|
-
assert "sa-token-python" in output
|
|
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
|
{sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/__init__.py
RENAMED
|
File without changes
|
{sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/fastapi.py
RENAMED
|
File without changes
|
{sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/integration/fastapi_oauth2.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/src/sa_token/security/temp_token.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
|
|
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
|
{sa_token_python_core-0.1.4 → sa_token_python_core-0.1.5}/tests/test_integration_fastapi_oauth2.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|