feat: 添加后台登录验证码、记住密码功能,优化媒体资源与前端规范
- 新增后台登录图形验证码功能,完善登录安全防护 - 新增登录rememberMe参数,控制Refresh Token的会话持久化策略 - 实现OSS私有桶媒体URL自动签名,统一处理图片资源的临时访问签名 - 新增素材库数据库表与上传API,规范媒体资源管理流程 - 统一前端UI图标使用@element-plus/icons-vue,重构布局图标组件 - 登录页新增验证码输入、刷新功能,添加账号记忆与记住密码逻辑 - 更新全套文档,补充API契约、技术决策记录与集成流程说明 - 修复多个业务页面的图标展示问题,新增认证流程相关测试用例
This commit is contained in:
1 parent
2c8c327de7
commit
6245159e7c
35 files changed
+914
-79
No files matched your search
@@ -0,0 +1,49 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import html
|
||||
import secrets
|
||||
from uuid import uuid4
|
||||
|
||||
from .redis_session import AdminSessionStore
|
||||
|
||||
CAPTCHA_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"
|
||||
|
||||
|
||||
def _captcha_code(length: int = 4) -> str:
|
||||
return "".join(secrets.choice(CAPTCHA_ALPHABET) for _ in range(length))
|
||||
|
||||
|
||||
def _captcha_image(code: str) -> str:
|
||||
lines = "".join(
|
||||
f'<path d="M{secrets.randbelow(150) + 5},{secrets.randbelow(42) + 3} '
|
||||
f'L{secrets.randbelow(150) + 5},{secrets.randbelow(42) + 3}" />'
|
||||
for _ in range(5)
|
||||
)
|
||||
safe_code = html.escape(code)
|
||||
svg = (
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" width="160" height="48" viewBox="0 0 160 48">'
|
||||
'<rect width="160" height="48" rx="4" fill="#f5f7fa"/>'
|
||||
f'<g stroke="#c0c4cc" stroke-width="1" opacity=".8">{lines}</g>'
|
||||
f'<text x="80" y="32" text-anchor="middle" fill="#303133" '
|
||||
'font-family="Arial,sans-serif" font-size="24" font-weight="700" letter-spacing="5">'
|
||||
f"{safe_code}</text></svg>"
|
||||
)
|
||||
encoded = base64.b64encode(svg.encode("utf-8")).decode("ascii")
|
||||
return f"data:image/svg+xml;base64,{encoded}"
|
||||
|
||||
|
||||
def create_captcha(store: AdminSessionStore, ttl_seconds: int) -> dict[str, object]:
|
||||
captcha_id = uuid4().hex
|
||||
code = _captcha_code()
|
||||
store.create_captcha(captcha_id, code, ttl_seconds)
|
||||
return {
|
||||
"captchaEnabled": True,
|
||||
"captchaId": captcha_id,
|
||||
"image": _captcha_image(code),
|
||||
"expiresIn": ttl_seconds,
|
||||
}
|
||||
|
||||
|
||||
def verify_captcha(store: AdminSessionStore, captcha_id: str, code: str) -> bool:
|
||||
return store.consume_captcha(captcha_id, code)
|
||||
Reference in new issue
Block a user