mirror of
https://github.com/lfnovo/open-notebook.git
synced 2026-05-20 09:02:22 +00:00
chore: prepare online wechat deployment
This commit is contained in:
parent
2e2a903a0b
commit
e638d245b7
6 changed files with 92 additions and 0 deletions
|
|
@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Added
|
||||
- Add WeChat Open Platform QR-code authentication for web login and registration, including OAuth callback handling, user binding/creation, i18n error messaging, and environment variable configuration.
|
||||
|
||||
### Changed
|
||||
- Respect `ALLOW_PUBLIC_REGISTRATION` when auto-creating first-time WeChat users.
|
||||
|
||||
## [1.8.4] - 2026-04-09
|
||||
|
||||
### Security
|
||||
|
|
|
|||
|
|
@ -52,6 +52,15 @@ def _wechat_redirect_uri() -> Optional[str]:
|
|||
return os.getenv("WECHAT_OPEN_REDIRECT_URI") or os.getenv("WECHAT_REDIRECT_URI")
|
||||
|
||||
|
||||
def _allow_wechat_user_creation() -> bool:
|
||||
return os.getenv("ALLOW_PUBLIC_REGISTRATION", "false").lower() in {
|
||||
"true",
|
||||
"1",
|
||||
"yes",
|
||||
"on",
|
||||
}
|
||||
|
||||
|
||||
async def build_wechat_authorize_url(state: str) -> WeChatAuthorizeUrlResponse:
|
||||
app_id = _wechat_app_id()
|
||||
redirect_uri = _wechat_redirect_uri()
|
||||
|
|
@ -167,6 +176,9 @@ async def handle_wechat_callback(request: WeChatCallbackRequest) -> LoginRespons
|
|||
updated = await UserRepository.update_user(user_id, updates)
|
||||
user = updated[0] if updated else {**user, **updates}
|
||||
else:
|
||||
if not _allow_wechat_user_creation():
|
||||
raise HTTPException(status_code=403, detail="Public registration is disabled")
|
||||
|
||||
user = await UserRepository.create_wechat_user(
|
||||
{
|
||||
"username": _username_from_wechat(user_info),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,13 @@ OPEN_NOTEBOOK_CORS_ORIGINS=https://lumina.yinhour.com
|
|||
OPEN_NOTEBOOK_AUTH_MODE=jwt
|
||||
ALLOW_PUBLIC_REGISTRATION=false
|
||||
|
||||
# Optional WeChat Open Platform web login.
|
||||
# The redirect URI must be registered in WeChat exactly as shown here.
|
||||
# If ALLOW_PUBLIC_REGISTRATION=false, WeChat can only sign in existing bound users.
|
||||
WECHAT_OPEN_APP_ID=
|
||||
WECHAT_OPEN_APP_SECRET=
|
||||
WECHAT_OPEN_REDIRECT_URI=https://lumina.yinhour.com/login/wechat/callback
|
||||
|
||||
# Required for saving AI provider credentials.
|
||||
OPEN_NOTEBOOK_ENCRYPTION_KEY=CHANGE_ME_generate_with_openssl_rand_base64_48
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,16 @@ openssl rand -base64 32
|
|||
|
||||
Keep `OPEN_NOTEBOOK_AUTH_MODE=jwt` for any Internet-facing site. Keep `ALLOW_PUBLIC_REGISTRATION=false` unless you intentionally want public signups.
|
||||
|
||||
Optional WeChat QR-code login uses a WeChat Open Platform website application:
|
||||
|
||||
```bash
|
||||
WECHAT_OPEN_APP_ID=...
|
||||
WECHAT_OPEN_APP_SECRET=...
|
||||
WECHAT_OPEN_REDIRECT_URI=https://lumina.yinhour.com/login/wechat/callback
|
||||
```
|
||||
|
||||
Register the same redirect URI in WeChat Open Platform. With `ALLOW_PUBLIC_REGISTRATION=false`, WeChat sign-in is limited to existing bound users; set it to `true` only if first-time WeChat users should be able to create accounts.
|
||||
|
||||
## 6. Install App Dependencies and Build Frontend
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -22,6 +22,20 @@ Comprehensive list of all environment variables available in Open Notebook.
|
|||
|
||||
---
|
||||
|
||||
## WeChat Web Login
|
||||
|
||||
WeChat web login uses a WeChat Open Platform website application and the frontend callback page at `/login/wechat/callback`.
|
||||
|
||||
| Variable | Required? | Default | Description |
|
||||
|----------|-----------|---------|-------------|
|
||||
| `WECHAT_OPEN_APP_ID` | Required for WeChat login | None | WeChat Open Platform website application AppID. Legacy alias: `WECHAT_APP_ID` |
|
||||
| `WECHAT_OPEN_APP_SECRET` | Required for callback token exchange | None | WeChat Open Platform website application AppSecret. Supports `_FILE` secret loading via `WECHAT_OPEN_APP_SECRET_FILE`; legacy alias: `WECHAT_APP_SECRET` |
|
||||
| `WECHAT_OPEN_REDIRECT_URI` | Required for WeChat login | None | Full frontend callback URL registered in WeChat, for example `https://lumina.yinhour.com/login/wechat/callback`. Legacy alias: `WECHAT_REDIRECT_URI` |
|
||||
|
||||
If `ALLOW_PUBLIC_REGISTRATION=false`, WeChat can sign in existing bound users but will not auto-create accounts for new WeChat identities.
|
||||
|
||||
---
|
||||
|
||||
## Email Verification
|
||||
|
||||
Open Notebook uses email verification for public registration and password reset.
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ async def test_handle_wechat_callback_logs_in_existing_bound_user(monkeypatch):
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_wechat_callback_creates_user_for_new_wechat_identity(monkeypatch):
|
||||
monkeypatch.setenv("ALLOW_PUBLIC_REGISTRATION", "true")
|
||||
created_user = {
|
||||
"id": "app_user:wx_openid_2",
|
||||
"username": "wx_openid_2",
|
||||
|
|
@ -138,3 +139,48 @@ async def test_handle_wechat_callback_creates_user_for_new_wechat_identity(monke
|
|||
assert create_payload["display_name"] == "New WeChat User"
|
||||
assert create_payload["wechat_openid"] == "openid-2"
|
||||
assert create_payload["avatar_url"] == "https://example.com/new-avatar.jpg"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_wechat_callback_blocks_new_user_when_public_registration_disabled(monkeypatch):
|
||||
monkeypatch.setenv("ALLOW_PUBLIC_REGISTRATION", "false")
|
||||
monkeypatch.setattr(
|
||||
wechat_auth_service,
|
||||
"_exchange_code_for_tokens",
|
||||
AsyncMock(
|
||||
return_value=WeChatOAuthTokens(
|
||||
access_token="wx-token",
|
||||
openid="openid-3",
|
||||
unionid=None,
|
||||
)
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
wechat_auth_service,
|
||||
"_fetch_user_info",
|
||||
AsyncMock(
|
||||
return_value=WeChatUserInfo(
|
||||
openid="openid-3",
|
||||
unionid=None,
|
||||
nickname="Blocked WeChat User",
|
||||
headimgurl=None,
|
||||
)
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
wechat_auth_service.UserRepository,
|
||||
"get_user_by_wechat_identity",
|
||||
AsyncMock(return_value=None),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
wechat_auth_service.UserRepository,
|
||||
"create_wechat_user",
|
||||
AsyncMock(),
|
||||
)
|
||||
|
||||
with pytest.raises(wechat_auth_service.HTTPException) as exc_info:
|
||||
await handle_wechat_callback(WeChatCallbackRequest(code="auth-code", state=None))
|
||||
|
||||
assert exc_info.value.status_code == 403
|
||||
assert exc_info.value.detail == "Public registration is disabled"
|
||||
wechat_auth_service.UserRepository.create_wechat_user.assert_not_awaited()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue