chore: add .gitignore, clean tracked junk files
This commit is contained in:
+53
@@ -0,0 +1,53 @@
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.pyo
|
||||
*.pyc
|
||||
*.egg-info/
|
||||
dist/
|
||||
build/
|
||||
|
||||
# Virtualenv
|
||||
venv/
|
||||
env/
|
||||
.venv/
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
"app/.env copy"
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# uWSGI
|
||||
uwsgi.pid
|
||||
uwsgi.sock
|
||||
uwsgi.log
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Uploads (keep directory, ignore contents)
|
||||
static/uploads/*
|
||||
!static/uploads/.gitkeep
|
||||
|
||||
# Supervisor
|
||||
*.conf
|
||||
!app/supervisor.conf
|
||||
|
||||
# Backup
|
||||
backup/
|
||||
|
||||
# Captcha
|
||||
app/static/captcha.png
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 激活虚拟环境
|
||||
VENV_PATH="/mnt/nfs/.venv"
|
||||
if [ -d "$VENV_PATH" ]; then
|
||||
source "$VENV_PATH/bin/activate"
|
||||
else
|
||||
echo "虚拟环境路径不存在:$VENV_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 定义 uWSGI 的启动配置文件路径
|
||||
INI_FILE="/opt/1panel/docker/compose/4an/app/uwsgi.ini"
|
||||
|
||||
# 定义 uWSGI 的 PID 文件路径
|
||||
PID_FILE="/opt/1panel/docker/compose/4an/uwsgi.pid"
|
||||
|
||||
# 定义日志文件路径
|
||||
LOG_FILE="/opt/1panel/docker/compose/4an/uwsgi.log"
|
||||
|
||||
# 检查配置文件是否存在
|
||||
if [ ! -f "$INI_FILE" ]; then
|
||||
echo "uWSGI 配置文件不存在:$INI_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查 PID 文件是否存在
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
echo "停止 uWSGI 服务..."
|
||||
uwsgi --stop "$PID_FILE"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "uWSGI 服务已成功停止。"
|
||||
else
|
||||
echo "停止 uWSGI 服务失败,请检查 PID 文件:$PID_FILE"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "PID 文件不存在,跳过停止服务步骤。"
|
||||
fi
|
||||
@@ -1,60 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 激活虚拟环境
|
||||
VENV_PATH="/mnt/nfs/.venv"
|
||||
if [ -d "$VENV_PATH" ]; then
|
||||
source "$VENV_PATH/bin/activate"
|
||||
else
|
||||
echo "虚拟环境路径不存在:$VENV_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 定义 uWSGI 的启动配置文件路径
|
||||
INI_FILE="/opt/1panel/docker/compose/4an/app/uwsgi.ini"
|
||||
|
||||
# 定义 uWSGI 的 PID 文件路径
|
||||
PID_FILE="/opt/1panel/docker/compose/4an/uwsgi.pid"
|
||||
|
||||
# 定义日志文件路径
|
||||
LOG_FILE="/opt/1panel/docker/compose/4an/uwsgi.log"
|
||||
|
||||
# 检查配置文件是否存在
|
||||
if [ ! -f "$INI_FILE" ]; then
|
||||
echo "uWSGI 配置文件不存在:$INI_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查 PID 文件是否存在
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
echo "停止 uWSGI 服务..."
|
||||
uwsgi --stop "$PID_FILE"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "uWSGI 服务已成功停止。"
|
||||
else
|
||||
echo "停止 uWSGI 服务失败,请检查 PID 文件:$PID_FILE"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "PID 文件不存在,跳过停止服务步骤。"
|
||||
fi
|
||||
|
||||
# 等待 2 秒,确保服务已完全停止
|
||||
sleep 2
|
||||
|
||||
# 启动 uWSGI 服务
|
||||
echo "启动 uWSGI 服务..."
|
||||
uwsgi --ini "$INI_FILE" --pidfile "$PID_FILE" --logto "$LOG_FILE"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "uWSGI 服务已成功启动。"
|
||||
else
|
||||
echo "uWSGI 服务启动失败,请检查日志:$LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查 PID 文件是否重新生成
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
echo "uWSGI 服务已成功重启。"
|
||||
else
|
||||
echo "uWSGI 服务启动失败,PID 文件未生成。"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,162 +0,0 @@
|
||||
# 4AN项目部署指南
|
||||
|
||||
## 环境变量配置
|
||||
|
||||
配置文件`app/config.py`已更新为支持环境变量。所有配置项可通过环境变量设置,包括:
|
||||
|
||||
- `SECRET_KEY`: 应用密钥
|
||||
- `DATABASE_URI`: 数据库连接URI
|
||||
- `LZMX_WEBHOOK_URL`: 临猪消息Webhook
|
||||
- `UPLOAD_FOLDER`: 文件上传目录
|
||||
- `KEY110_DB_HOST`: 1key110数据库主机
|
||||
- `KEY110_DB_USER`: 1key110数据库用户
|
||||
- `KEY110_DB_PASSWORD`: 1key110数据库密码
|
||||
- `KEY110_DB_DATABASE`: 1key110数据库名称
|
||||
|
||||
## 使用Supervisor管理项目
|
||||
|
||||
### 安装依赖
|
||||
|
||||
项目需要安装python-dotenv包以支持环境变量:
|
||||
|
||||
```bash
|
||||
/mnt/nfs/.venv/bin/pip install python-dotenv
|
||||
```
|
||||
|
||||
### 环境变量文件
|
||||
|
||||
我们已创建环境变量文件 `/opt/1panel/docker/compose/4an/4an.env`,其中包含所有配置参数:
|
||||
|
||||
```
|
||||
# 应用密钥
|
||||
SECRET_KEY=
|
||||
|
||||
# 数据库连接
|
||||
DATABASE_URI=mysql+pymysql://4an:GtbJp6Ai5azntnTB@10.10.10.253/4an
|
||||
|
||||
# 临猪消息Webhook
|
||||
LZMX_WEBHOOK_URL=http://imtwo.zdxlz.com/im-external/v1/webhook/send?key=ef1dc605827f425e96491ce5725b5274
|
||||
|
||||
# 文件上传目录
|
||||
UPLOAD_FOLDER=static/uploads
|
||||
|
||||
# 1key110数据库配置
|
||||
KEY110_DB_HOST=10.10.10.253
|
||||
KEY110_DB_USER=1key110
|
||||
KEY110_DB_PASSWORD=KzdKtf7KfkXe7iCN
|
||||
KEY110_DB_DATABASE=1key110
|
||||
```
|
||||
|
||||
在启动应用前需要加载这些环境变量:
|
||||
|
||||
```bash
|
||||
# 加载环境变量文件
|
||||
export $(cat /opt/1panel/docker/compose/4an/4an.env | grep -v '^#' | xargs)
|
||||
```
|
||||
|
||||
### 配置Supervisor
|
||||
|
||||
1. 确保修改app/config.py使其支持环境变量后,再使用Supervisor管理应用
|
||||
|
||||
2. 将`4an_supervisor.conf`文件复制到Supervisor配置目录:
|
||||
|
||||
```bash
|
||||
sudo cp 4an_supervisor.conf /etc/supervisor/conf.d/
|
||||
```
|
||||
|
||||
3. 在配置文件目录中创建一个启动脚本,用于加载环境变量并启动应用:
|
||||
|
||||
```bash
|
||||
sudo nano /opt/1panel/docker/compose/4an/start_with_env.sh
|
||||
```
|
||||
|
||||
脚本内容:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 加载环境变量
|
||||
export $(cat /opt/1panel/docker/compose/4an/4an.env | grep -v '^#' | xargs)
|
||||
|
||||
# 启动uwsgi
|
||||
exec /mnt/nfs/.venv/bin/uwsgi --ini /opt/1panel/docker/compose/4an/app/uwsgi.ini
|
||||
```
|
||||
|
||||
设置脚本权限:
|
||||
|
||||
```bash
|
||||
sudo chmod +x /opt/1panel/docker/compose/4an/start_with_env.sh
|
||||
```
|
||||
|
||||
4. 修改Supervisor配置使用该脚本:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/supervisor/conf.d/4an_supervisor.conf
|
||||
```
|
||||
|
||||
将command行修改为:
|
||||
|
||||
```
|
||||
command=/opt/1panel/docker/compose/4an/start_with_env.sh
|
||||
```
|
||||
|
||||
5. 更新Supervisor配置:
|
||||
|
||||
```bash
|
||||
sudo supervisorctl reread
|
||||
sudo supervisorctl update
|
||||
```
|
||||
|
||||
6. 管理4an服务:
|
||||
|
||||
```bash
|
||||
# 启动服务
|
||||
sudo supervisorctl start 4an
|
||||
|
||||
# 停止服务
|
||||
sudo supervisorctl stop 4an
|
||||
|
||||
# 重启服务
|
||||
sudo supervisorctl restart 4an
|
||||
|
||||
# 查看服务状态
|
||||
sudo supervisorctl status 4an
|
||||
|
||||
# 查看日志
|
||||
sudo tail -f /opt/1panel/docker/compose/4an/supervisor.log
|
||||
```
|
||||
|
||||
## 使用systemd(可选)
|
||||
|
||||
如果需要使用systemd而不是Supervisor,可以创建服务文件:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/systemd/system/4an.service
|
||||
```
|
||||
|
||||
服务文件内容示例:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=4AN Application
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=root
|
||||
WorkingDirectory=/opt/1panel/docker/compose/4an/app
|
||||
ExecStart=/mnt/nfs/.venv/bin/uwsgi --ini /opt/1panel/docker/compose/4an/app/uwsgi.ini
|
||||
Restart=always
|
||||
StandardOutput=file:/opt/1panel/docker/compose/4an/systemd.log
|
||||
StandardError=file:/opt/1panel/docker/compose/4an/systemd_error.log
|
||||
EnvironmentFile=/opt/1panel/docker/compose/4an/4an.env
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
然后启用并启动服务:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable 4an
|
||||
sudo systemctl start 4an
|
||||
```
|
||||
@@ -1,14 +0,0 @@
|
||||
[program:4an]
|
||||
command=/mnt/nfs/.venv/bin/uwsgi --ini /opt/1panel/docker/compose/4an/app/uwsgi.ini
|
||||
directory=/opt/1panel/docker/compose/4an/app
|
||||
user=root
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stopasgroup=true
|
||||
killasgroup=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/opt/1panel/docker/compose/4an/supervisor.log
|
||||
stdout_logfile_maxbytes=10MB
|
||||
stdout_logfile_backups=5
|
||||
environment=PYTHONPATH="/opt/1panel/docker/compose/4an/app"
|
||||
environment_file=/opt/1panel/docker/compose/4an/.env
|
||||
@@ -1,454 +0,0 @@
|
||||
# Casdoor 集成经验总结
|
||||
|
||||
本文档总结了在 Flask 项目中集成 Casdoor 并使用现有登录页面时遇到的所有问题和解决方案,帮助后续项目避免踩坑。
|
||||
|
||||
## 目录
|
||||
|
||||
1. [集成方式选择](#集成方式选择)
|
||||
2. [配置步骤](#配置步骤)
|
||||
3. [常见问题与解决方案](#常见问题与解决方案)
|
||||
4. [最佳实践](#最佳实践)
|
||||
5. [代码示例](#代码示例)
|
||||
|
||||
---
|
||||
|
||||
## 集成方式选择
|
||||
|
||||
### 方式一:OAuth 重定向方式(不推荐用于现有登录页面)
|
||||
|
||||
**特点:**
|
||||
- 用户点击登录后跳转到 Casdoor 登录页面
|
||||
- 登录成功后回调到项目
|
||||
- 适合新项目或不需要保留现有登录页面的场景
|
||||
|
||||
**缺点:**
|
||||
- 无法使用项目现有的登录页面
|
||||
- 用户体验不够统一
|
||||
|
||||
### 方式二:API 方式(推荐)
|
||||
|
||||
**特点:**
|
||||
- 使用 OAuth 2.0 password grant 方式
|
||||
- 在项目现有登录页面输入用户名密码
|
||||
- 通过 API 直接验证,无需跳转
|
||||
- 用户体验更好,界面统一
|
||||
|
||||
**推荐使用方式二**
|
||||
|
||||
---
|
||||
|
||||
## 配置步骤
|
||||
|
||||
### 1. 环境变量配置
|
||||
|
||||
在 `.env` 文件或系统环境变量中添加:
|
||||
|
||||
```bash
|
||||
# Casdoor 服务地址
|
||||
CASDOOR_ENDPOINT=https://your-casdoor-server.com
|
||||
|
||||
# Casdoor 应用配置(在 Casdoor 管理界面创建应用后获取)
|
||||
CASDOOR_CLIENT_ID=your_client_id
|
||||
CASDOOR_CLIENT_SECRET=your_client_secret
|
||||
|
||||
# 组织名称和应用名称(通常在 Casdoor 中配置)
|
||||
CASDOOR_ORGANIZATION_NAME=your_organization
|
||||
CASDOOR_APPLICATION_NAME=your_application
|
||||
|
||||
# 会话 Cookie 配置(跨域 SSO 时建议设置)
|
||||
SESSION_COOKIE_SAMESITE=Lax # 或 None(跨域时)
|
||||
SESSION_COOKIE_SECURE=False # HTTPS 时设为 True
|
||||
```
|
||||
|
||||
### 2. 在 Casdoor 中创建应用
|
||||
|
||||
1. 登录 Casdoor 管理界面
|
||||
2. 进入 "Applications" 页面
|
||||
3. 创建新应用,记录 `Client ID` 和 `Client Secret`
|
||||
4. **重要**:确保应用启用了 password grant 方式(如果 Casdoor 版本支持)
|
||||
|
||||
### 3. 代码集成
|
||||
|
||||
参考项目中的以下文件:
|
||||
- `app/utils/casdoor_auth.py` - Casdoor 认证工具类
|
||||
- `app/views/auth.py` - 认证路由处理
|
||||
- `app/templates/login.html` - 登录页面模板
|
||||
|
||||
---
|
||||
|
||||
## 常见问题与解决方案
|
||||
|
||||
### 问题 1:登录后提示 "Please log in to access this page"
|
||||
|
||||
**原因:**
|
||||
- Flask-Login 的默认提示消息是英文
|
||||
- 登录成功后可能有残留的 flash 消息
|
||||
|
||||
**解决方案:**
|
||||
|
||||
在 `app.py` 中配置 Flask-Login:
|
||||
|
||||
```python
|
||||
login_manager = LoginManager()
|
||||
login_manager.init_app(app)
|
||||
login_manager.login_view = 'login'
|
||||
login_manager.login_message = '请先登录以访问此页面' # 设置中文提示
|
||||
login_manager.login_message_category = 'info'
|
||||
```
|
||||
|
||||
在登录成功后清除 flash 消息:
|
||||
|
||||
```python
|
||||
# 在 auth.py 的登录成功处理中
|
||||
session.pop('_flashes', None)
|
||||
```
|
||||
|
||||
在模板中过滤已登录用户的未登录提示:
|
||||
|
||||
```html
|
||||
<!-- base.html -->
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
{% if not (current_user.is_authenticated and '请先登录' in message) %}
|
||||
<!-- 显示消息 -->
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
```
|
||||
|
||||
### 问题 2:API 登录返回 "Unauthorized operation"
|
||||
|
||||
**原因:**
|
||||
- 使用了错误的 API 端点
|
||||
- 参数格式不正确
|
||||
- 未使用 OAuth 2.0 password grant 方式
|
||||
|
||||
**解决方案:**
|
||||
|
||||
使用正确的 OAuth 2.0 password grant 端点:
|
||||
|
||||
```python
|
||||
login_url = f"{endpoint}/api/login/oauth/access_token"
|
||||
|
||||
data = {
|
||||
'grant_type': 'password', # 必须指定 grant_type
|
||||
'username': username,
|
||||
'password': password,
|
||||
'client_id': client_id, # 必须包含 client_id
|
||||
'client_secret': client_secret, # 必须包含 client_secret
|
||||
'scope': 'openid profile email phone'
|
||||
}
|
||||
```
|
||||
|
||||
**注意:** 某些 Casdoor 版本可能不支持 password grant,需要检查 Casdoor 文档或使用 OAuth 授权码方式。
|
||||
|
||||
### 问题 3:退出时跳转到 Casdoor 404 页面
|
||||
|
||||
**原因:**
|
||||
- 退出时尝试跳转到 Casdoor 的退出页面
|
||||
- Casdoor 退出 URL 不正确
|
||||
|
||||
**解决方案:**
|
||||
|
||||
如果不需要同时退出 Casdoor,只退出本地会话:
|
||||
|
||||
```python
|
||||
@app.route('/logout')
|
||||
@login_required
|
||||
def logout():
|
||||
logout_user()
|
||||
return redirect(url_for('login'))
|
||||
```
|
||||
|
||||
如果需要同时退出 Casdoor,使用正确的退出 URL:
|
||||
|
||||
```python
|
||||
# 注意:需要确保 redirect_uri 在 Casdoor 应用的回调白名单中
|
||||
logout_url = f"{casdoor_endpoint}/login/oauth/logout?client_id={client_id}&redirect_uri={login_url}"
|
||||
```
|
||||
|
||||
### 问题 4:语法错误 - try-except 块不匹配
|
||||
|
||||
**原因:**
|
||||
- 代码重构时 try 块未正确闭合
|
||||
- 在 try 块外使用了 try 块内定义的变量
|
||||
|
||||
**解决方案:**
|
||||
|
||||
确保所有逻辑都在完整的 try-except 块中:
|
||||
|
||||
```python
|
||||
try:
|
||||
# 所有逻辑代码
|
||||
response = requests.post(...)
|
||||
result = response.json()
|
||||
# ... 处理逻辑
|
||||
return result
|
||||
except requests.exceptions.Timeout:
|
||||
# 处理超时
|
||||
return None
|
||||
except requests.exceptions.RequestException as e:
|
||||
# 处理请求异常
|
||||
return None
|
||||
except Exception as e:
|
||||
# 处理其他异常
|
||||
return None
|
||||
```
|
||||
|
||||
**检查要点:**
|
||||
- 每个 `try` 必须有对应的 `except` 或 `finally`
|
||||
- 变量作用域要正确(在 try 块内定义的变量不能在块外使用)
|
||||
|
||||
### 问题 5:API 响应格式解析错误
|
||||
|
||||
**原因:**
|
||||
- Casdoor API 返回格式可能不同
|
||||
- 未处理各种可能的响应格式
|
||||
|
||||
**解决方案:**
|
||||
|
||||
兼容多种响应格式:
|
||||
|
||||
```python
|
||||
result = response.json()
|
||||
|
||||
# 检查错误
|
||||
if isinstance(result, dict) and result.get('status') == 'error':
|
||||
error_msg = result.get('msg', '未知错误')
|
||||
return None
|
||||
|
||||
# 尝试多种格式获取 token
|
||||
access_token = None
|
||||
if isinstance(result, dict):
|
||||
# 标准 OAuth 2.0 格式
|
||||
access_token = result.get('access_token')
|
||||
|
||||
# Casdoor 格式 {"status": "ok", "data": {...}}
|
||||
if not access_token and result.get('status') == 'ok':
|
||||
token_data = result.get('data', {})
|
||||
if isinstance(token_data, dict):
|
||||
access_token = token_data.get('access_token')
|
||||
|
||||
# 其他可能的字段
|
||||
if not access_token:
|
||||
access_token = result.get('token') or result.get('accessToken')
|
||||
```
|
||||
|
||||
### 问题 6:用户信息同步问题
|
||||
|
||||
**原因:**
|
||||
- Casdoor 返回的用户信息字段名可能不同
|
||||
- 本地数据库字段映射不正确
|
||||
|
||||
**解决方案:**
|
||||
|
||||
使用多个可能的字段名:
|
||||
|
||||
```python
|
||||
# 从 Casdoor 用户信息中提取数据
|
||||
casdoor_id = user_info.get('sub') or user_info.get('id') or user_info.get('name')
|
||||
phone = user_info.get('phone') or user_info.get('phoneNumber') or casdoor_id
|
||||
name = user_info.get('name') or user_info.get('displayName') or username
|
||||
branch = user_info.get('affiliation', '')
|
||||
role = user_info.get('type', '')
|
||||
```
|
||||
|
||||
### 问题 7:会话 Cookie 配置问题
|
||||
|
||||
**原因:**
|
||||
- 跨域时 Cookie 无法正确设置
|
||||
- SameSite 和 Secure 属性配置不当
|
||||
|
||||
**解决方案:**
|
||||
|
||||
在 `config.py` 中配置:
|
||||
|
||||
```python
|
||||
# 跨域 SSO 时
|
||||
SESSION_COOKIE_SAMESITE = 'None' # 需要配合 Secure=True
|
||||
SESSION_COOKIE_SECURE = True # HTTPS 必须
|
||||
|
||||
# 同域时
|
||||
SESSION_COOKIE_SAMESITE = 'Lax'
|
||||
SESSION_COOKIE_SECURE = False # HTTP 开发环境
|
||||
```
|
||||
|
||||
**注意:** `SameSite=None` 必须配合 `Secure=True` 使用,且需要 HTTPS。
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 错误处理
|
||||
|
||||
- 始终使用 try-except 包裹 API 调用
|
||||
- 记录详细的错误日志,便于排查
|
||||
- 对用户显示友好的错误提示
|
||||
|
||||
```python
|
||||
try:
|
||||
result = casdoor_auth.login_with_password(username, password)
|
||||
if not result:
|
||||
flash('用户名或密码错误')
|
||||
return render_template('login.html')
|
||||
except Exception as e:
|
||||
app.logger.error(f"登录异常: {str(e)}")
|
||||
flash('登录失败,请稍后重试')
|
||||
return render_template('login.html')
|
||||
```
|
||||
|
||||
### 2. 日志记录
|
||||
|
||||
- 记录登录尝试(不记录密码)
|
||||
- 记录 API 调用结果
|
||||
- 记录用户信息同步情况
|
||||
|
||||
```python
|
||||
app.logger.info(f"尝试 Casdoor API 登录: username={username}")
|
||||
app.logger.info(f"Casdoor 用户信息: {user_info}")
|
||||
app.logger.info(f"用户 {user.name}({user.phone}) 通过 Casdoor API 登录成功")
|
||||
```
|
||||
|
||||
### 3. 安全性
|
||||
|
||||
- 永远不要在日志中记录密码
|
||||
- 使用 HTTPS(生产环境)
|
||||
- 验证和清理用户输入
|
||||
- 使用环境变量存储敏感配置
|
||||
|
||||
### 4. 用户体验
|
||||
|
||||
- 提供清晰的错误提示
|
||||
- 登录成功后清除残留的提示消息
|
||||
- 保持登录页面的原有样式
|
||||
|
||||
### 5. 代码组织
|
||||
|
||||
- 将 Casdoor 相关逻辑封装在独立的工具类中
|
||||
- 保持路由处理简洁
|
||||
- 使用配置类管理所有配置项
|
||||
|
||||
---
|
||||
|
||||
## 代码示例
|
||||
|
||||
### 完整的认证工具类结构
|
||||
|
||||
```python
|
||||
# app/utils/casdoor_auth.py
|
||||
class CasdoorAuth:
|
||||
def __init__(self, app=None):
|
||||
self.app = app
|
||||
if app:
|
||||
self.init_app(app)
|
||||
|
||||
def init_app(self, app):
|
||||
"""初始化应用配置"""
|
||||
self.endpoint = app.config.get('CASDOOR_ENDPOINT')
|
||||
self.client_id = app.config.get('CASDOOR_CLIENT_ID')
|
||||
self.client_secret = app.config.get('CASDOOR_CLIENT_SECRET')
|
||||
self.organization_name = app.config.get('CASDOOR_ORGANIZATION_NAME', 'built-in')
|
||||
self.application_name = app.config.get('CASDOOR_APPLICATION_NAME', 'app-built-in')
|
||||
|
||||
def login_with_password(self, username, password):
|
||||
"""使用用户名和密码通过 API 登录"""
|
||||
login_url = f"{self.endpoint}/api/login/oauth/access_token"
|
||||
data = {
|
||||
'grant_type': 'password',
|
||||
'username': username,
|
||||
'password': password,
|
||||
'client_id': self.client_id,
|
||||
'client_secret': self.client_secret,
|
||||
'scope': 'openid profile email phone'
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(login_url, data=data, timeout=10)
|
||||
# ... 处理响应
|
||||
except Exception as e:
|
||||
# ... 错误处理
|
||||
return None
|
||||
|
||||
def get_user_info(self, access_token):
|
||||
"""使用访问令牌获取用户信息"""
|
||||
# ... 实现
|
||||
pass
|
||||
```
|
||||
|
||||
### 登录路由处理
|
||||
|
||||
```python
|
||||
# app/views/auth.py
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
if request.method == 'POST':
|
||||
username = request.form.get('username', '').strip()
|
||||
password = request.form.get('password', '').strip()
|
||||
|
||||
if not username or not password:
|
||||
flash('请输入用户名和密码')
|
||||
return render_template('login.html')
|
||||
|
||||
# 使用 API 方式登录
|
||||
result = casdoor_auth.login_with_password(username, password)
|
||||
|
||||
if not result:
|
||||
flash('用户名或密码错误')
|
||||
return render_template('login.html')
|
||||
|
||||
# 处理用户信息同步
|
||||
user_info = result.get('user_info', {})
|
||||
# ... 创建或更新用户
|
||||
|
||||
login_user(user)
|
||||
session.pop('_flashes', None) # 清除残留提示
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
return render_template('login.html')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 检查清单
|
||||
|
||||
在集成 Casdoor 时,确保完成以下检查:
|
||||
|
||||
- [ ] 环境变量配置正确
|
||||
- [ ] Casdoor 应用已创建并获取 Client ID 和 Secret
|
||||
- [ ] 使用正确的 API 端点(`/api/login/oauth/access_token`)
|
||||
- [ ] 使用 OAuth 2.0 password grant 方式
|
||||
- [ ] 所有 try-except 块正确闭合
|
||||
- [ ] 错误处理完善,有详细的日志记录
|
||||
- [ ] 登录成功后清除残留的 flash 消息
|
||||
- [ ] 用户信息同步逻辑正确
|
||||
- [ ] 会话 Cookie 配置正确(跨域时)
|
||||
- [ ] 登录页面样式保持一致
|
||||
- [ ] 测试各种错误场景(错误密码、网络错误等)
|
||||
|
||||
---
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [Casdoor 官方文档](https://casdoor.org/docs/overview)
|
||||
- [OAuth 2.0 Password Grant](https://oauth.net/2/grant-types/password/)
|
||||
- [Flask-Login 文档](https://flask-login.readthedocs.io/)
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
集成 Casdoor 到现有项目时,主要注意以下几点:
|
||||
|
||||
1. **选择正确的集成方式**:API 方式更适合保留现有登录页面
|
||||
2. **使用正确的 API 端点和参数**:OAuth 2.0 password grant 方式
|
||||
3. **完善的错误处理**:处理各种异常情况和响应格式
|
||||
4. **用户体验优化**:清除残留提示,保持界面统一
|
||||
5. **安全性考虑**:使用 HTTPS,不在日志中记录敏感信息
|
||||
|
||||
遵循以上实践,可以避免大部分常见问题,顺利完成 Casdoor 集成。
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
# Casdoor 集成配置指南
|
||||
|
||||
本文档将指导您如何配置 Casdoor 作为项目的登录认证系统。
|
||||
|
||||
## 前置条件
|
||||
|
||||
1. 已通过 1Panel 部署 Casdoor 服务
|
||||
2. Casdoor 服务可以正常访问
|
||||
3. 拥有 Casdoor 管理员权限
|
||||
|
||||
## 第一步:在 Casdoor 中创建应用
|
||||
|
||||
1. **登录 Casdoor 管理界面**
|
||||
- 访问您的 Casdoor 地址(例如:`http://your-server:8000`)
|
||||
- 使用管理员账户登录(默认:`admin` / `123`)
|
||||
|
||||
2. **创建应用(Application)**
|
||||
- 进入 "Applications" 页面
|
||||
- 点击 "Add" 按钮创建新应用
|
||||
- 填写以下信息:
|
||||
- **Name**: 应用名称(例如:`4an-app`)
|
||||
- **Display name**: 显示名称(例如:`4AN 工单管理系统`)
|
||||
- **Organization**: 选择组织(默认:`built-in`)
|
||||
- **Enable password**: 是否启用密码登录(根据需要选择)
|
||||
- **Enable sign up**: 是否允许注册(根据需要选择)
|
||||
|
||||
3. **配置回调 URL(Redirect URI)**
|
||||
- 在应用配置中找到 "Redirect URLs" 或 "Redirect URI"
|
||||
- 添加您的应用回调地址,例如:
|
||||
```
|
||||
http://your-app-server:18061/callback
|
||||
```
|
||||
- 如果有多个环境,可以添加多个回调地址
|
||||
|
||||
4. **记录应用凭证**
|
||||
- 创建应用后,Casdoor 会生成:
|
||||
- **Client ID**: 客户端 ID
|
||||
- **Client Secret**: 客户端密钥
|
||||
- 请妥善保存这些信息,后续配置需要使用
|
||||
|
||||
## 第二步:配置项目环境变量
|
||||
|
||||
在您的环境变量文件(`.env` 或系统环境变量)中添加以下配置:
|
||||
|
||||
```bash
|
||||
# Casdoor 配置
|
||||
CASDOOR_ENDPOINT=http://your-casdoor-server:8000
|
||||
CASDOOR_CLIENT_ID=your_client_id_here
|
||||
CASDOOR_CLIENT_SECRET=your_client_secret_here
|
||||
CASDOOR_ORGANIZATION_NAME=built-in
|
||||
CASDOOR_APPLICATION_NAME=your_app_name
|
||||
CASDOOR_REDIRECT_URI=http://your-app-server:18061/callback
|
||||
```
|
||||
|
||||
### 配置说明
|
||||
|
||||
- `CASDOOR_ENDPOINT`: Casdoor 服务的完整地址(不包含路径)
|
||||
- `CASDOOR_CLIENT_ID`: 在 Casdoor 中创建应用时获得的 Client ID
|
||||
- `CASDOOR_CLIENT_SECRET`: 在 Casdoor 中创建应用时获得的 Client Secret
|
||||
- `CASDOOR_ORGANIZATION_NAME`: 组织名称(默认:`built-in`)
|
||||
- `CASDOOR_APPLICATION_NAME`: 应用名称(与 Casdoor 中创建的应用名称一致)
|
||||
- `CASDOOR_REDIRECT_URI`: 回调地址,必须与 Casdoor 应用中配置的 Redirect URI 完全一致
|
||||
|
||||
## 第三步:安装依赖
|
||||
|
||||
确保已安装所有必要的 Python 依赖:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
主要依赖包括:
|
||||
- `requests`: 用于与 Casdoor API 通信
|
||||
- `Flask-Login`: 用于会话管理
|
||||
- 其他项目依赖
|
||||
|
||||
## 第四步:在 Casdoor 中创建用户
|
||||
|
||||
1. **创建用户**
|
||||
- 进入 Casdoor 的 "Users" 页面
|
||||
- 点击 "Add" 创建新用户
|
||||
- 填写用户信息:
|
||||
- **Name**: 用户名(唯一标识)
|
||||
- **Display name**: 显示名称
|
||||
- **Email**: 邮箱(可选)
|
||||
- **Phone**: 手机号(建议填写,用于与本地用户表关联)
|
||||
- **Password**: 密码
|
||||
- **Organization**: 选择组织
|
||||
|
||||
2. **关联用户到应用**
|
||||
- 在用户详情页面,确保用户属于正确的组织
|
||||
- 用户登录后会自动同步到本地数据库
|
||||
|
||||
## 第五步:测试登录
|
||||
|
||||
1. **启动应用**
|
||||
```bash
|
||||
python app/app.py
|
||||
# 或使用 uwsgi/supervisor 启动
|
||||
```
|
||||
|
||||
2. **访问登录页面**
|
||||
- 访问 `http://your-app-server:18061/login`
|
||||
- 您应该看到两个登录选项:
|
||||
- "使用 Casdoor 登录" 按钮(如果配置了 Casdoor)
|
||||
- 手机号登录表单(备用方案)
|
||||
|
||||
3. **测试 Casdoor 登录**
|
||||
- 点击 "使用 Casdoor 登录" 按钮
|
||||
- 应该重定向到 Casdoor 登录页面
|
||||
- 使用 Casdoor 中的用户账户登录
|
||||
- 登录成功后应该重定向回应用并自动登录
|
||||
|
||||
## 用户信息同步
|
||||
|
||||
当用户通过 Casdoor 首次登录时,系统会:
|
||||
|
||||
1. 从 Casdoor 获取用户信息
|
||||
2. 检查本地数据库中是否存在该用户(通过手机号匹配)
|
||||
3. 如果不存在,创建新用户记录
|
||||
4. 如果存在,更新用户信息(姓名、支局、角色等)
|
||||
|
||||
用户信息映射:
|
||||
- `phone`: 从 Casdoor 的 `phone` 或 `phoneNumber` 字段获取
|
||||
- `name`: 从 Casdoor 的 `name` 或 `displayName` 字段获取
|
||||
- `branch`: 从 Casdoor 的 `affiliation` 字段获取
|
||||
- `role`: 从 Casdoor 的 `type` 字段获取
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 问题:点击 Casdoor 登录按钮没有反应或报错
|
||||
|
||||
**解决方案**:
|
||||
1. 检查环境变量是否正确配置
|
||||
2. 检查 `CASDOOR_ENDPOINT` 是否可以访问
|
||||
3. 检查 `CASDOOR_CLIENT_ID` 和 `CASDOOR_CLIENT_SECRET` 是否正确
|
||||
4. 查看应用日志获取详细错误信息
|
||||
|
||||
### 问题:登录后回调失败
|
||||
|
||||
**解决方案**:
|
||||
1. 确保 `CASDOOR_REDIRECT_URI` 与 Casdoor 应用中配置的完全一致
|
||||
2. 检查回调地址是否可以从 Casdoor 服务器访问
|
||||
3. 检查防火墙和网络配置
|
||||
|
||||
### 问题:无法获取用户信息
|
||||
|
||||
**解决方案**:
|
||||
1. 检查 Casdoor 应用配置中的 Scope 是否包含 `openid profile email phone`
|
||||
2. 检查用户是否有正确的权限
|
||||
3. 查看应用日志中的详细错误信息
|
||||
|
||||
### 问题:用户信息同步失败
|
||||
|
||||
**解决方案**:
|
||||
1. 确保 Casdoor 用户信息中包含手机号(phone)
|
||||
2. 检查数据库连接是否正常
|
||||
3. 查看应用日志获取详细错误信息
|
||||
|
||||
## 安全建议
|
||||
|
||||
1. **保护 Client Secret**
|
||||
- 不要将 `CASDOOR_CLIENT_SECRET` 提交到代码仓库
|
||||
- 使用环境变量或密钥管理服务存储敏感信息
|
||||
|
||||
2. **使用 HTTPS**
|
||||
- 生产环境建议使用 HTTPS
|
||||
- 更新 `CASDOOR_ENDPOINT` 和 `CASDOOR_REDIRECT_URI` 为 HTTPS 地址
|
||||
|
||||
3. **定期更新密码**
|
||||
- 定期更新 Casdoor 管理员密码
|
||||
- 定期轮换 Client Secret
|
||||
|
||||
4. **监控日志**
|
||||
- 定期检查应用日志,关注认证失败的情况
|
||||
- 设置告警机制
|
||||
|
||||
## 更多信息
|
||||
|
||||
- Casdoor 官方文档:https://casdoor.org/docs/overview
|
||||
- Casdoor GitHub:https://github.com/casbin/casdoor
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 如果未配置 Casdoor(未设置 `CASDOOR_CLIENT_ID`),系统会自动使用原有的手机号登录方式
|
||||
2. 两种登录方式可以并存,用户可以选择使用哪种方式登录
|
||||
3. 用户信息会从 Casdoor 同步到本地数据库,确保数据一致性
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
SECRET_KEY=kU/W5y3uFbWuK1x+RTTOPgLp38yM6Z7d
|
||||
|
||||
# 数据库连接
|
||||
DATABASE_URI=mysql+pymysql://4an:GtbJp6Ai5azntnTB@10.10.10.14/4an
|
||||
SQLALCHEMY_DATABASE_URI=mysql+pymysql://4an:GtbJp6Ai5azntnTB@10.10.10.14/4an
|
||||
|
||||
# 量子密信消息Webhook
|
||||
LZMX_WEBHOOK_URL=http://imtwo.zdxlz.com/im-external/v1/webhook/send?key=ef1dc605827f425e96491ce5725b5274
|
||||
@@ -42,3 +42,4 @@ CASDOOR_CLIENT_SECRET=bc37d89f9220fe5a46c17125c731d2daf22f1299
|
||||
CASDOOR_REDIRECT_URI=https://zd.dhdx.fun/callback
|
||||
CASDOOR_ORGANIZATION_NAME=dahua
|
||||
CASDOOR_APPLICATION_NAME=4an
|
||||
PROJECT_NAME=4an
|
||||
Binary file not shown.
Binary file not shown.
@@ -16,6 +16,7 @@ import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
import os
|
||||
from utils.error_handlers import ErrorHandler
|
||||
from utils.db_utils import retry_database_connection
|
||||
|
||||
def create_app():
|
||||
# 创建应用实例
|
||||
@@ -49,6 +50,12 @@ def create_app():
|
||||
|
||||
# 初始化数据库
|
||||
db.init_app(app)
|
||||
|
||||
# 确保数据库连接成功后再继续启动
|
||||
app.logger.info("正在连接数据库...")
|
||||
if not retry_database_connection(db, app):
|
||||
raise RuntimeError("无法连接到数据库,应用启动失败")
|
||||
|
||||
migrate = Migrate(app, db)
|
||||
|
||||
# 初始化异常处理器
|
||||
|
||||
+22
-2
@@ -1,7 +1,14 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# 加载.env文件 (相对于应用根目录)
|
||||
# 尽量兼容多种 .env 放置方式
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent # /home/.../4an
|
||||
# 1. 优先加载项目根目录 .env
|
||||
load_dotenv(BASE_DIR / '.env')
|
||||
# 2. 兼容放在 app 目录下的 .env
|
||||
load_dotenv(BASE_DIR / 'app' / '.env')
|
||||
# 3. 再加载一次默认搜索路径(当前工作目录及其父级)
|
||||
load_dotenv()
|
||||
|
||||
|
||||
@@ -10,7 +17,18 @@ class Config:
|
||||
环境变量优先级高于默认值,可在系统环境变量中设置这些参数
|
||||
"""
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY', os.urandom(24))
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI')
|
||||
# 优先读取 SQLALCHEMY_DATABASE_URI,兼容旧配置;否则回退到 DATABASE_URI
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI') or os.environ.get('DATABASE_URI')
|
||||
SQLALCHEMY_ENGINE_OPTIONS = {
|
||||
'pool_pre_ping': True, # 每次取连接前验证是否可用
|
||||
'pool_recycle': 1800, # 连接空闲 30 分钟后自动回收重建
|
||||
'pool_timeout': 10, # 等待连接池超时(秒)
|
||||
'connect_args': {
|
||||
'connect_timeout': 5, # 连接 MySQL 超时
|
||||
'read_timeout': 15, # 读取超时
|
||||
'write_timeout': 15, # 写入超时
|
||||
},
|
||||
}
|
||||
LZMX_WEBHOOK_URL = os.environ.get('LZMX_WEBHOOK_URL')
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER', 'static/uploads')
|
||||
@@ -31,6 +49,8 @@ class Config:
|
||||
CASDOOR_ORGANIZATION_NAME = os.environ.get('CASDOOR_ORGANIZATION_NAME', 'built-in')
|
||||
CASDOOR_APPLICATION_NAME = os.environ.get('CASDOOR_APPLICATION_NAME', 'app-built-in')
|
||||
CASDOOR_REDIRECT_URI = os.environ.get('CASDOOR_REDIRECT_URI', 'http://localhost:18061/callback')
|
||||
# 项目名称(用于与 Casdoor 用户标签匹配权限)
|
||||
PROJECT_NAME = os.environ.get('PROJECT_NAME')
|
||||
|
||||
# 会话 Cookie 配置(跨域 SSO 时建议设置)
|
||||
SESSION_COOKIE_SAMESITE = os.environ.get('SESSION_COOKIE_SAMESITE', 'Lax')
|
||||
|
||||
-1101
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB |
@@ -26,10 +26,14 @@
|
||||
<p style="margin-top: 12px; color: #666;">正在跳转至 Casdoor 登录页,如未跳转请点击按钮。</p>
|
||||
</div>
|
||||
<script>
|
||||
// 有错误提示时停留在本页,方便用户查看信息
|
||||
const hasError = {{ 'true' if get_flashed_messages() else 'false' }};
|
||||
if (!hasError) {
|
||||
// 自动跳转至 Casdoor 登录
|
||||
window.onload = function() {
|
||||
window.location.href = "{{ url_for('casdoor_login') }}";
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -108,6 +108,34 @@ class CasdoorAuth:
|
||||
pass # 如果无法记录日志,忽略错误
|
||||
return None
|
||||
|
||||
def get_account_info(self, access_token):
|
||||
"""
|
||||
使用访问令牌获取完整账户信息(包含标签等字段)
|
||||
"""
|
||||
account_url = f"{self.endpoint}/api/get-account"
|
||||
headers = {
|
||||
'Authorization': f'Bearer {access_token}'
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.get(account_url, headers=headers)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
# Casdoor 通常返回 {"status": "ok", "data": {...}}
|
||||
if isinstance(result, dict):
|
||||
if result.get('status') == 'ok' and isinstance(result.get('data'), dict):
|
||||
return result['data']
|
||||
if 'data' in result and isinstance(result.get('data'), dict):
|
||||
return result['data']
|
||||
return result if isinstance(result, dict) else None
|
||||
except requests.exceptions.RequestException as e:
|
||||
try:
|
||||
current_app.logger.error(f"获取 Casdoor 账户信息失败: {str(e)}")
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
def verify_state(self, state):
|
||||
"""
|
||||
验证 state 参数,防止 CSRF 攻击
|
||||
|
||||
@@ -3,6 +3,7 @@ import time
|
||||
from flask import current_app
|
||||
import logging
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy import text
|
||||
from scripts.models import db
|
||||
from collections import defaultdict
|
||||
|
||||
@@ -121,6 +122,44 @@ def clear_table_cache(table_name):
|
||||
if key in query_cache.access_times:
|
||||
del query_cache.access_times[key]
|
||||
|
||||
# 数据库连接重试机制
|
||||
def retry_database_connection(db_instance, app, max_retries=10, retry_delay=5):
|
||||
"""
|
||||
尝试连接数据库,在连接失败时进行重试
|
||||
:param db_instance: SQLAlchemy数据库实例
|
||||
:param app: Flask应用实例
|
||||
:param max_retries: 最大重试次数
|
||||
:param retry_delay: 重试间隔(秒)
|
||||
:return: 连接成功返回True,失败返回False
|
||||
"""
|
||||
import sqlalchemy.exc as sa_exc
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
app.logger.info(f"尝试连接数据库... (尝试 {attempt + 1}/{max_retries})")
|
||||
|
||||
# 使用with语句确保应用上下文正确
|
||||
with app.app_context():
|
||||
# 尝试建立连接 - SQLAlchemy 2.0 兼容方式
|
||||
with db_instance.engine.connect() as connection:
|
||||
connection.execute(text("SELECT 1"))
|
||||
connection.commit() # 确保事务提交
|
||||
|
||||
app.logger.info("数据库连接成功!")
|
||||
return True
|
||||
|
||||
except (sa_exc.OperationalError, sa_exc.DatabaseError, Exception) as e:
|
||||
app.logger.warning(f"数据库连接失败: {str(e)}")
|
||||
|
||||
if attempt < max_retries - 1:
|
||||
app.logger.info(f"等待 {retry_delay} 秒后重试...")
|
||||
time.sleep(retry_delay)
|
||||
else:
|
||||
app.logger.error(f"数据库连接失败,已重试 {max_retries} 次,放弃连接")
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
# 通用查询函数,包含异常处理和缓存
|
||||
@db_operation()
|
||||
@cache_query()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+29
-5
@@ -13,8 +13,8 @@ def init_auth_routes(app):
|
||||
# 如果已登录,直接跳转到仪表盘
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('dashboard'))
|
||||
# 未登录直接跳转 Casdoor 登录页
|
||||
return redirect(url_for('casdoor_login'))
|
||||
# 未登录展示登录页(登录页会自动跳转 Casdoor,如有错误提示则不跳转)
|
||||
return render_template('login.html')
|
||||
|
||||
@app.route('/casdoor/login')
|
||||
def casdoor_login():
|
||||
@@ -65,18 +65,44 @@ def init_auth_routes(app):
|
||||
flash('登录失败:无法获取用户信息')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
# 获取完整账户信息(包含标签)
|
||||
account_info = casdoor_auth.get_account_info(access_token)
|
||||
if not account_info:
|
||||
app.logger.error('获取 Casdoor 账户信息失败')
|
||||
flash('登录失败:无法获取账户信息')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
# 从 Casdoor 用户信息中提取数据
|
||||
# Casdoor 返回的用户信息可能包含:name, email, phone, id 等字段
|
||||
casdoor_id = user_info.get('sub') or user_info.get('id') or user_info.get('name')
|
||||
phone = user_info.get('phone') or user_info.get('phoneNumber') or casdoor_id
|
||||
name = user_info.get('name') or user_info.get('displayName') or '未知用户'
|
||||
|
||||
# 基于标签的访问控制:用户标签必须等于项目名
|
||||
project_name = app.config.get('PROJECT_NAME')
|
||||
if not project_name:
|
||||
app.logger.error('未配置 PROJECT_NAME 环境变量,拒绝登录')
|
||||
flash('登录失败:未配置项目名')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
raw_tags = account_info.get('tag') or account_info.get('tags')
|
||||
if isinstance(raw_tags, str):
|
||||
user_tags = [t.strip() for t in raw_tags.split(',') if t.strip()]
|
||||
elif isinstance(raw_tags, list):
|
||||
user_tags = [str(t).strip() for t in raw_tags if str(t).strip()]
|
||||
else:
|
||||
user_tags = []
|
||||
|
||||
if project_name not in user_tags:
|
||||
app.logger.warning(f'用户 {name}({phone}) 标签 {user_tags} 不匹配项目 {project_name}')
|
||||
flash('您没有本系统的访问权限,请联系管理员处理')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
app.logger.info(f'Casdoor 用户信息: {user_info}')
|
||||
|
||||
# 查找或创建本地用户
|
||||
user = User.query.filter_by(phone=phone).first()
|
||||
if not user:
|
||||
# 如果用户不存在,创建新用户
|
||||
user = User(
|
||||
phone=phone,
|
||||
name=name,
|
||||
@@ -87,7 +113,6 @@ def init_auth_routes(app):
|
||||
db.session.commit()
|
||||
app.logger.info(f'创建新用户: {name}({phone})')
|
||||
else:
|
||||
# 更新用户信息
|
||||
user.name = name
|
||||
if user_info.get('affiliation'):
|
||||
user.branch = user_info.get('affiliation')
|
||||
@@ -96,7 +121,6 @@ def init_auth_routes(app):
|
||||
db.session.commit()
|
||||
app.logger.info(f'更新用户信息: {name}({phone})')
|
||||
|
||||
# 登录用户
|
||||
login_user(user)
|
||||
app.logger.info(f'用户 {user.name}({user.phone}) 通过 Casdoor 登录成功')
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 加载环境变量
|
||||
export $(cat /opt/1panel/docker/compose/4an/.env | grep -v '^#' | xargs)
|
||||
|
||||
# 启动uwsgi
|
||||
exec /mnt/nfs/.venv/bin/uwsgi --ini /opt/1panel/docker/compose/4an/app/uwsgi.ini
|
||||
@@ -1,407 +0,0 @@
|
||||
[2025-12-11 22:21:50,347] ERROR in error_handlers: 未处理异常: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
Traceback (most recent call last):
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/4an/app/views/auth.py", line 17, in login
|
||||
return redirect(url_for('casdoor_login'))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/helpers.py", line 239, in url_for
|
||||
return current_app.url_for(
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
|
||||
return self.handle_url_build_error(error, endpoint, values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
|
||||
rv = url_adapter.build( # type: ignore[union-attr]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
|
||||
raise BuildError(endpoint, values, method, self)
|
||||
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
|
||||
[2025-12-11 22:21:51,162] ERROR in error_handlers: 未处理异常: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
Traceback (most recent call last):
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/4an/app/views/auth.py", line 17, in login
|
||||
return redirect(url_for('casdoor_login'))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/helpers.py", line 239, in url_for
|
||||
return current_app.url_for(
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
|
||||
return self.handle_url_build_error(error, endpoint, values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
|
||||
rv = url_adapter.build( # type: ignore[union-attr]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
|
||||
raise BuildError(endpoint, values, method, self)
|
||||
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
|
||||
[2025-12-11 22:21:53,765] ERROR in error_handlers: 未处理异常: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
Traceback (most recent call last):
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/4an/app/views/auth.py", line 17, in login
|
||||
return redirect(url_for('casdoor_login'))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/helpers.py", line 239, in url_for
|
||||
return current_app.url_for(
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
|
||||
return self.handle_url_build_error(error, endpoint, values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
|
||||
rv = url_adapter.build( # type: ignore[union-attr]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
|
||||
raise BuildError(endpoint, values, method, self)
|
||||
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
|
||||
[2025-12-11 22:21:55,427] ERROR in error_handlers: 未处理异常: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
Traceback (most recent call last):
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/4an/app/views/auth.py", line 17, in login
|
||||
return redirect(url_for('casdoor_login'))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/helpers.py", line 239, in url_for
|
||||
return current_app.url_for(
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
|
||||
return self.handle_url_build_error(error, endpoint, values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
|
||||
rv = url_adapter.build( # type: ignore[union-attr]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
|
||||
raise BuildError(endpoint, values, method, self)
|
||||
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
|
||||
[2025-12-11 22:21:56,245] ERROR in error_handlers: 未处理异常: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
Traceback (most recent call last):
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/4an/app/views/auth.py", line 17, in login
|
||||
return redirect(url_for('casdoor_login'))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/helpers.py", line 239, in url_for
|
||||
return current_app.url_for(
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
|
||||
return self.handle_url_build_error(error, endpoint, values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
|
||||
rv = url_adapter.build( # type: ignore[union-attr]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
|
||||
raise BuildError(endpoint, values, method, self)
|
||||
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
|
||||
[2025-12-11 22:21:57,458] ERROR in error_handlers: 未处理异常: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
Traceback (most recent call last):
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/4an/app/views/auth.py", line 17, in login
|
||||
return redirect(url_for('casdoor_login'))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/helpers.py", line 239, in url_for
|
||||
return current_app.url_for(
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
|
||||
return self.handle_url_build_error(error, endpoint, values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
|
||||
rv = url_adapter.build( # type: ignore[union-attr]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
|
||||
raise BuildError(endpoint, values, method, self)
|
||||
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
|
||||
[2025-12-11 22:21:58,265] ERROR in error_handlers: 未处理异常: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
Traceback (most recent call last):
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/4an/app/views/auth.py", line 17, in login
|
||||
return redirect(url_for('casdoor_login'))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/helpers.py", line 239, in url_for
|
||||
return current_app.url_for(
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
|
||||
return self.handle_url_build_error(error, endpoint, values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
|
||||
rv = url_adapter.build( # type: ignore[union-attr]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
|
||||
raise BuildError(endpoint, values, method, self)
|
||||
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
|
||||
[2025-12-11 22:21:59,973] ERROR in error_handlers: 未处理异常: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
Traceback (most recent call last):
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/4an/app/views/auth.py", line 17, in login
|
||||
return redirect(url_for('casdoor_login'))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/helpers.py", line 239, in url_for
|
||||
return current_app.url_for(
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
|
||||
return self.handle_url_build_error(error, endpoint, values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
|
||||
rv = url_adapter.build( # type: ignore[union-attr]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
|
||||
raise BuildError(endpoint, values, method, self)
|
||||
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
|
||||
[2025-12-11 22:22:01,191] ERROR in error_handlers: 未处理异常: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
Traceback (most recent call last):
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/4an/app/views/auth.py", line 17, in login
|
||||
return redirect(url_for('casdoor_login'))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/helpers.py", line 239, in url_for
|
||||
return current_app.url_for(
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
|
||||
return self.handle_url_build_error(error, endpoint, values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
|
||||
rv = url_adapter.build( # type: ignore[union-attr]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
|
||||
raise BuildError(endpoint, values, method, self)
|
||||
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'casdoor_login'. Did you mean 'casdoor_callback' instead?
|
||||
|
||||
[uwsgi-python-reloader] module/file /home/v6ole/pyproject/4an/app/views/auth.py has been modified
|
||||
[uwsgi-python-reloader] module/file /home/v6ole/pyproject/4an/app/views/auth.py has been modified
|
||||
[uwsgi-python-reloader] module/file /home/v6ole/pyproject/4an/app/views/auth.py has been modified
|
||||
[uwsgi-python-reloader] module/file /home/v6ole/pyproject/4an/app/views/auth.py has been modified
|
||||
gateway "uWSGI http 1" has been buried (pid: 2840701)
|
||||
...gracefully killing workers...
|
||||
Gracefully killing worker 1 (pid: 2840688)...
|
||||
Gracefully killing worker 3 (pid: 2840692)...
|
||||
Gracefully killing worker 4 (pid: 2840695)...
|
||||
Gracefully killing worker 2 (pid: 2840691)...
|
||||
worker 1 buried after 1 seconds
|
||||
worker 2 buried after 1 seconds
|
||||
worker 3 buried after 1 seconds
|
||||
worker 4 buried after 1 seconds
|
||||
binary reloading uWSGI...
|
||||
chdir() to /home/v6ole/pyproject/4an
|
||||
closing all non-uwsgi socket fds > 2 (max_fd = 1024)...
|
||||
found fd 9 mapped to socket 0 (/home/v6ole/pyproject/4an/uwsgi.sock)
|
||||
running /home/v6ole/pyproject/venv/bin/uwsgi
|
||||
[uWSGI] getting INI configuration from /home/v6ole/pyproject/4an/app/uwsgi.ini
|
||||
*** Starting uWSGI 2.0.31 (64bit) on [Thu Dec 11 22:23:17 2025] ***
|
||||
compiled with version: 13.3.0 on 26 November 2025 03:29:52
|
||||
os: Linux-6.8.0-88-generic #89-Ubuntu SMP PREEMPT_DYNAMIC Sat Oct 11 01:02:46 UTC 2025
|
||||
nodename: fnubserver
|
||||
machine: x86_64
|
||||
clock source: unix
|
||||
detected number of CPU cores: 22
|
||||
current working directory: /home/v6ole/pyproject/4an
|
||||
detected binary path: /home/v6ole/pyproject/venv/bin/uwsgi
|
||||
!!! no internal routing support, rebuild with pcre support !!!
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
chdir() to /home/v6ole/pyproject/4an/app
|
||||
your processes number limit is 63617
|
||||
your memory page size is 4096 bytes
|
||||
*** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers ***
|
||||
detected max file descriptor number: 1024
|
||||
lock engine: pthread robust mutexes
|
||||
thunder lock: disabled (you can enable it with --thunder-lock)
|
||||
uWSGI http bound on 0.0.0.0:18019 fd 7
|
||||
probably another instance of uWSGI is running on the same address (0.0.0.0:18019).
|
||||
bind(): Address already in use [core/socket.c line 769]
|
||||
VACUUM: pidfile removed.
|
||||
*** Starting uWSGI 2.0.31 (64bit) on [Thu Dec 11 22:23:18 2025] ***
|
||||
compiled with version: 13.3.0 on 26 November 2025 03:29:52
|
||||
os: Linux-6.8.0-88-generic #89-Ubuntu SMP PREEMPT_DYNAMIC Sat Oct 11 01:02:46 UTC 2025
|
||||
nodename: fnubserver
|
||||
machine: x86_64
|
||||
clock source: unix
|
||||
detected number of CPU cores: 22
|
||||
current working directory: /home/v6ole/pyproject/4an
|
||||
writing pidfile to /home/v6ole/pyproject/4an/uwsgi.pid
|
||||
detected binary path: /home/v6ole/pyproject/venv/bin/uwsgi
|
||||
!!! no internal routing support, rebuild with pcre support !!!
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
chdir() to /home/v6ole/pyproject/4an/app
|
||||
your processes number limit is 63617
|
||||
your memory page size is 4096 bytes
|
||||
*** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers ***
|
||||
detected max file descriptor number: 1024
|
||||
lock engine: pthread robust mutexes
|
||||
thunder lock: disabled (you can enable it with --thunder-lock)
|
||||
uWSGI http bound on 0.0.0.0:18019 fd 6
|
||||
uwsgi socket 0 bound to UNIX address /home/v6ole/pyproject/4an/uwsgi.sock fd 9
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
Python version: 3.12.3 (main, Nov 6 2025, 13:44:16) [GCC 13.3.0]
|
||||
PEP 405 virtualenv detected: /home/v6ole/pyproject/venv
|
||||
Set PythonHome to /home/v6ole/pyproject/venv
|
||||
Python main interpreter initialized at 0x78df1aea3668
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
python threads support enabled
|
||||
your server socket listen backlog is limited to 100 connections
|
||||
your mercy for graceful operations on workers is 60 seconds
|
||||
mapped 703440 bytes (686 KB) for 8 cores
|
||||
*** Operational MODE: preforking+threaded ***
|
||||
[2025-12-11 22:23:19,123] INFO in app: 应用启动
|
||||
[2025-12-11 22:23:19,124] INFO in error_handlers: 错误处理器初始化完成
|
||||
WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x78df1aea3668 pid: 2854900 (default app)
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
*** uWSGI is running in multiple interpreter mode ***
|
||||
spawned uWSGI master process (pid: 2854900)
|
||||
spawned uWSGI worker 1 (pid: 2855094, cores: 2)
|
||||
Python auto-reloader enabled
|
||||
spawned uWSGI worker 2 (pid: 2855098, cores: 2)
|
||||
spawned uWSGI worker 3 (pid: 2855101, cores: 2)
|
||||
spawned uWSGI worker 4 (pid: 2855102, cores: 2)
|
||||
*** Stats server enabled on 127.0.0.1:9191 fd: 22 ***
|
||||
spawned uWSGI http 1 (pid: 2855106)
|
||||
unable to stat() uwsgi.reload, events will be triggered as soon as the file is created
|
||||
unable to stat() true, events will be triggered as soon as the file is created
|
||||
[2025-12-11 22:23:29,628] INFO in auth: 重定向到 Casdoor 授权页面
|
||||
[uwsgi-python-reloader] module/file /home/v6ole/pyproject/4an/app/views/auth.py has been modified
|
||||
[uwsgi-python-reloader] module/file /home/v6ole/pyproject/4an/app/views/auth.py has been modified
|
||||
gateway "uWSGI http 1" has been buried (pid: 2855106)
|
||||
...gracefully killing workers...
|
||||
Gracefully killing worker 2 (pid: 2855098)...
|
||||
Gracefully killing worker 3 (pid: 2855101)...
|
||||
Gracefully killing worker 4 (pid: 2855102)...
|
||||
Gracefully killing worker 1 (pid: 2855094)...
|
||||
worker 1 buried after 1 seconds
|
||||
worker 2 buried after 1 seconds
|
||||
worker 3 buried after 1 seconds
|
||||
worker 4 buried after 1 seconds
|
||||
binary reloading uWSGI...
|
||||
chdir() to /home/v6ole/pyproject/4an
|
||||
closing all non-uwsgi socket fds > 2 (max_fd = 1024)...
|
||||
found fd 9 mapped to socket 0 (/home/v6ole/pyproject/4an/uwsgi.sock)
|
||||
running /home/v6ole/pyproject/venv/bin/uwsgi
|
||||
[uWSGI] getting INI configuration from /home/v6ole/pyproject/4an/app/uwsgi.ini
|
||||
*** Starting uWSGI 2.0.31 (64bit) on [Thu Dec 11 22:23:36 2025] ***
|
||||
compiled with version: 13.3.0 on 26 November 2025 03:29:52
|
||||
os: Linux-6.8.0-88-generic #89-Ubuntu SMP PREEMPT_DYNAMIC Sat Oct 11 01:02:46 UTC 2025
|
||||
nodename: fnubserver
|
||||
machine: x86_64
|
||||
clock source: unix
|
||||
detected number of CPU cores: 22
|
||||
current working directory: /home/v6ole/pyproject/4an
|
||||
detected binary path: /home/v6ole/pyproject/venv/bin/uwsgi
|
||||
!!! no internal routing support, rebuild with pcre support !!!
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
chdir() to /home/v6ole/pyproject/4an/app
|
||||
your processes number limit is 63617
|
||||
your memory page size is 4096 bytes
|
||||
*** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers ***
|
||||
detected max file descriptor number: 1024
|
||||
lock engine: pthread robust mutexes
|
||||
thunder lock: disabled (you can enable it with --thunder-lock)
|
||||
uWSGI http bound on 0.0.0.0:18019 fd 7
|
||||
probably another instance of uWSGI is running on the same address (0.0.0.0:18019).
|
||||
bind(): Address already in use [core/socket.c line 769]
|
||||
VACUUM: pidfile removed.
|
||||
*** Starting uWSGI 2.0.31 (64bit) on [Thu Dec 11 22:23:37 2025] ***
|
||||
compiled with version: 13.3.0 on 26 November 2025 03:29:52
|
||||
os: Linux-6.8.0-88-generic #89-Ubuntu SMP PREEMPT_DYNAMIC Sat Oct 11 01:02:46 UTC 2025
|
||||
nodename: fnubserver
|
||||
machine: x86_64
|
||||
clock source: unix
|
||||
detected number of CPU cores: 22
|
||||
current working directory: /home/v6ole/pyproject/4an
|
||||
writing pidfile to /home/v6ole/pyproject/4an/uwsgi.pid
|
||||
detected binary path: /home/v6ole/pyproject/venv/bin/uwsgi
|
||||
!!! no internal routing support, rebuild with pcre support !!!
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
chdir() to /home/v6ole/pyproject/4an/app
|
||||
your processes number limit is 63617
|
||||
your memory page size is 4096 bytes
|
||||
*** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers ***
|
||||
detected max file descriptor number: 1024
|
||||
lock engine: pthread robust mutexes
|
||||
thunder lock: disabled (you can enable it with --thunder-lock)
|
||||
uWSGI http bound on 0.0.0.0:18019 fd 6
|
||||
uwsgi socket 0 bound to UNIX address /home/v6ole/pyproject/4an/uwsgi.sock fd 9
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
Python version: 3.12.3 (main, Nov 6 2025, 13:44:16) [GCC 13.3.0]
|
||||
PEP 405 virtualenv detected: /home/v6ole/pyproject/venv
|
||||
Set PythonHome to /home/v6ole/pyproject/venv
|
||||
Python main interpreter initialized at 0x7121faaa3668
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
python threads support enabled
|
||||
your server socket listen backlog is limited to 100 connections
|
||||
your mercy for graceful operations on workers is 60 seconds
|
||||
mapped 703440 bytes (686 KB) for 8 cores
|
||||
*** Operational MODE: preforking+threaded ***
|
||||
[2025-12-11 22:23:38,073] INFO in app: 应用启动
|
||||
[2025-12-11 22:23:38,074] INFO in error_handlers: 错误处理器初始化完成
|
||||
WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x7121faaa3668 pid: 2857150 (default app)
|
||||
uWSGI running as root, you can use --uid/--gid/--chroot options
|
||||
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
|
||||
*** uWSGI is running in multiple interpreter mode ***
|
||||
spawned uWSGI master process (pid: 2857150)
|
||||
spawned uWSGI worker 1 (pid: 2857296, cores: 2)
|
||||
spawned uWSGI worker 2 (pid: 2857300, cores: 2)
|
||||
Python auto-reloader enabled
|
||||
spawned uWSGI worker 3 (pid: 2857303, cores: 2)
|
||||
spawned uWSGI worker 4 (pid: 2857304, cores: 2)
|
||||
*** Stats server enabled on 127.0.0.1:9191 fd: 22 ***
|
||||
spawned uWSGI http 1 (pid: 2857309)
|
||||
unable to stat() uwsgi.reload, events will be triggered as soon as the file is created
|
||||
unable to stat() true, events will be triggered as soon as the file is created
|
||||
[2025-12-11 22:23:51,348] INFO in auth: Casdoor 用户信息: {'sub': '66d04f8e-e663-4ee1-a2e9-5777901c6df7', 'iss': 'https://casdoor.dhdx.fun', 'aud': '8f323670e073612794ef', 'preferred_username': 'weijuesen', 'name': '韦矍森', 'email': 'voole@vip.qq.com', 'email_verified': True, 'picture': 'https://cdn.casbin.org/img/casbin.svg', 'phone': '19977899008', 'real_name': '韦矍森', 'roles': ['admin']}
|
||||
[2025-12-11 22:23:51,367] INFO in auth: 更新用户信息: 韦矍森(19977899008)
|
||||
[2025-12-11 22:23:51,368] INFO in auth: 用户 韦矍森(19977899008) 通过 Casdoor 登录成功
|
||||
[2025-12-11 22:23:51,772] INFO in dashboard: 用户 韦矍森 访问仪表盘页面
|
||||
Reference in New Issue
Block a user