feat: embed permission claims in JWT and add captcha verification

- Add GroupClaims model for JWT permission snapshots
- Add JWTPayload model for typed JWT decoding
- Refactor auth middleware: jwt_required (no DB) -> admin_required (no DB) -> auth_required (DB)
- Add UserBanStore for instant ban enforcement via Redis + memory fallback
- Fix status check bug: StrEnum is always truthy, use explicit != ACTIVE
- Shorten access_token expiry from 3h to 1h
- Add CaptchaScene enum and verify_captcha_if_needed service
- Add require_captcha dependency injection factory
- Add CLA document and new default settings
- Update all tests for new JWT API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-10 19:07:00 +08:00
parent 209cb24ab4
commit a99091ea7a
20 changed files with 766 additions and 244 deletions

View File

@@ -188,6 +188,28 @@ class GroupListResponse(SQLModelBase):
"""总数"""
class GroupClaims(GroupCoreBase, GroupAllOptionsBase):
"""
JWT 中的用户组权限快照。
复用 GroupCoreBaseid, name, max_storage, share_enabled, web_dav_enabled, admin, speed_limit
和 GroupAllOptionsBaseshare_download, share_free, ... 共 11 个功能开关)。
"""
@classmethod
def from_group(cls, group: "Group") -> "GroupClaims":
"""
从 Group ORM 对象(需预加载 options 关系)构建权限快照。
:param group: 已加载 options 的 Group 对象
"""
opts = group.options
return cls(
**GroupCoreBase.model_validate(group, from_attributes=True).model_dump(),
**(GroupAllOptionsBase.model_validate(opts, from_attributes=True).model_dump() if opts else {}),
)
class GroupResponse(GroupBase, GroupOptionsBase):
"""用户组响应 DTO"""