支持从.env同步管理员密码;新增reset_admin.py
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+2
-1
@@ -6,9 +6,10 @@ DEBUG=false
|
|||||||
# Flask Session 密钥(部署时务必改为随机字符串,deploy.sh 首次会自动生成)
|
# Flask Session 密钥(部署时务必改为随机字符串,deploy.sh 首次会自动生成)
|
||||||
SECRET_KEY=change-this-to-a-random-secret-key
|
SECRET_KEY=change-this-to-a-random-secret-key
|
||||||
|
|
||||||
# 初始管理员账号(仅首次初始化数据库时写入,之后请在「系统设置」修改密码)
|
# 初始管理员(首次建库自动写入;已建库后修改需设 ADMIN_SYNC_FROM_ENV=true 并重启)
|
||||||
ADMIN_USERNAME=admin
|
ADMIN_USERNAME=admin
|
||||||
ADMIN_PASSWORD=change-me-on-first-login
|
ADMIN_PASSWORD=change-me-on-first-login
|
||||||
|
ADMIN_SYNC_FROM_ENV=false
|
||||||
|
|
||||||
# 企业微信 Webhook(也可在系统设置页面修改)
|
# 企业微信 Webhook(也可在系统设置页面修改)
|
||||||
WECHAT_WEBHOOK=
|
WECHAT_WEBHOOK=
|
||||||
|
|||||||
@@ -91,14 +91,19 @@ HOST=0.0.0.0
|
|||||||
PORT=6600
|
PORT=6600
|
||||||
SECRET_KEY=随机长字符串
|
SECRET_KEY=随机长字符串
|
||||||
ADMIN_USERNAME=admin
|
ADMIN_USERNAME=admin
|
||||||
ADMIN_PASSWORD=首次登录密码
|
ADMIN_PASSWORD=你的密码
|
||||||
|
ADMIN_SYNC_FROM_ENV=false
|
||||||
WECHAT_WEBHOOK=企业微信机器人地址(可选)
|
WECHAT_WEBHOOK=企业微信机器人地址(可选)
|
||||||
QUOTE_SOURCE=sina
|
QUOTE_SOURCE=sina
|
||||||
```
|
```
|
||||||
|
|
||||||
普通用户保持 `QUOTE_SOURCE=sina` 即可,无需配置同花顺 token。
|
**改密码说明**:账号存在 `futures.db` 里,改 `.env` 后不会自动生效。
|
||||||
|
|
||||||
> 管理员密码首次从 `.env` 写入数据库并哈希存储,之后请在「系统设置」中修改。
|
- **首次部署**:写好 `ADMIN_USERNAME` / `ADMIN_PASSWORD` 后启动即可。
|
||||||
|
- **已部署后**:在 `.env` 设 `ADMIN_SYNC_FROM_ENV=true`,改密码后 `pm2 restart qihuo`;或在网页「系统设置」改密。
|
||||||
|
- **忘记密码**:`source venv/bin/activate && python reset_admin.py`
|
||||||
|
|
||||||
|
普通用户保持 `QUOTE_SOURCE=sina` 即可。
|
||||||
|
|
||||||
### 5. PM2 启动
|
### 5. PM2 启动
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from werkzeug.security import check_password_hash, generate_password_hash
|
|||||||
from symbols import search_symbols, ths_to_codes
|
from symbols import search_symbols, ths_to_codes
|
||||||
from market import get_price as market_get_price, set_ths_refresh_token, get_quote_source_label
|
from market import get_price as market_get_price, set_ths_refresh_token, get_quote_source_label
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env"))
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = os.getenv("SECRET_KEY", "futures_monitor_default_secret")
|
app.secret_key = os.getenv("SECRET_KEY", "futures_monitor_default_secret")
|
||||||
@@ -96,11 +96,7 @@ def init_db():
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
if not get_setting("admin_username"):
|
sync_admin_from_env()
|
||||||
username = os.getenv("ADMIN_USERNAME", "admin")
|
|
||||||
password = os.getenv("ADMIN_PASSWORD", "admin123")
|
|
||||||
set_setting("admin_username", username)
|
|
||||||
set_setting("admin_password_hash", generate_password_hash(password))
|
|
||||||
|
|
||||||
if not get_setting("wechat_webhook") and os.getenv("WECHAT_WEBHOOK"):
|
if not get_setting("wechat_webhook") and os.getenv("WECHAT_WEBHOOK"):
|
||||||
set_setting("wechat_webhook", os.getenv("WECHAT_WEBHOOK"))
|
set_setting("wechat_webhook", os.getenv("WECHAT_WEBHOOK"))
|
||||||
@@ -109,6 +105,33 @@ def init_db():
|
|||||||
set_setting("ths_refresh_token", os.getenv("THS_REFRESH_TOKEN"))
|
set_setting("ths_refresh_token", os.getenv("THS_REFRESH_TOKEN"))
|
||||||
|
|
||||||
|
|
||||||
|
def sync_admin_from_env():
|
||||||
|
"""
|
||||||
|
从 .env 同步管理员账号。
|
||||||
|
- 首次建库:自动写入 ADMIN_USERNAME / ADMIN_PASSWORD
|
||||||
|
- 已建库后改 .env:需设 ADMIN_SYNC_FROM_ENV=true 并重启服务
|
||||||
|
"""
|
||||||
|
sync = os.getenv("ADMIN_SYNC_FROM_ENV", "false").lower() in ("1", "true", "yes")
|
||||||
|
env_username = os.getenv("ADMIN_USERNAME", "").strip()
|
||||||
|
env_password = os.getenv("ADMIN_PASSWORD", "").strip()
|
||||||
|
placeholder_passwords = {"", "change-me-on-first-login", "admin123"}
|
||||||
|
|
||||||
|
if not get_setting("admin_username"):
|
||||||
|
username = env_username or "admin"
|
||||||
|
password = env_password if env_password not in placeholder_passwords else "admin123"
|
||||||
|
set_setting("admin_username", username)
|
||||||
|
set_setting("admin_password_hash", generate_password_hash(password))
|
||||||
|
return
|
||||||
|
|
||||||
|
if not sync:
|
||||||
|
return
|
||||||
|
|
||||||
|
if env_username:
|
||||||
|
set_setting("admin_username", env_username)
|
||||||
|
if env_password and env_password not in placeholder_passwords:
|
||||||
|
set_setting("admin_password_hash", generate_password_hash(env_password))
|
||||||
|
|
||||||
|
|
||||||
init_db()
|
init_db()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""从 .env 重置管理员账号(服务器上忘记密码时使用)"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from werkzeug.security import generate_password_hash
|
||||||
|
|
||||||
|
BASE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
load_dotenv(os.path.join(BASE, ".env"))
|
||||||
|
|
||||||
|
sys.path.insert(0, BASE)
|
||||||
|
from app import set_setting, get_setting # noqa: E402
|
||||||
|
|
||||||
|
username = os.getenv("ADMIN_USERNAME", "admin").strip() or "admin"
|
||||||
|
password = os.getenv("ADMIN_PASSWORD", "").strip()
|
||||||
|
if not password or password == "change-me-on-first-login":
|
||||||
|
print("请在 .env 中设置 ADMIN_PASSWORD 后再运行此脚本")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
old_username = get_setting("admin_username")
|
||||||
|
set_setting("admin_username", username)
|
||||||
|
set_setting("admin_password_hash", generate_password_hash(password))
|
||||||
|
print(f"已重置管理员: {username}(原账号: {old_username or '无'})")
|
||||||
Reference in New Issue
Block a user