# Office 365 Self Service 基于 Microsoft Graph API 实现的 Office 365 账号自助开通系统。通过兑换码自助开通账号,每个兑换码只能开通一个账号。 ## 功能特性 - **兑换码管理**:管理员后台批量生成兑换码 - **自助开通**:用户输入兑换码和用户名自助开通 Office 365 账号 - **自动授权**:账号开通时自动分配许可证 - **兑换记录**:后台记录兑换码与已开通账号的对应关系 - **审计日志**:后台分页查看生成、删除、兑换成功/失败等关键事件 ## 项目结构 ``` . ├── app.py # 应用入口 ├── Dockerfile # Docker 镜像构建 ├── docker-compose.yml # Docker Compose 部署 ├── requirements.txt # Python 依赖 ├── .env.example # 配置示例 ├── office365_self_service/ │ ├── __init__.py # Flask 应用工厂 │ ├── settings.py # 配置加载 │ ├── routes.py # 路由定义 │ ├── models.py # 数据库模型 │ ├── services.py # Office 365 服务 │ ├── graph.py # Graph API 客户端 │ └── templates/ # 前端模板 │ ├── admin_login.html # 管理员登录 │ ├── admin_dashboard.html # 管理后台 │ └── user_redemption.html # 用户兑换页面 ``` ## 部署方式 ### 本地运行 ```bash # 1. 创建虚拟环境并安装依赖 python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt # 2. 复制配置文件 cp .env.example .env # 3. 在 .env 中填写配置(见下方参数说明) # 4. 启动服务 python3 app.py ``` 访问地址:http://127.0.0.1:8000 ### Docker Compose 部署 ```bash # 1. 复制配置文件并配置 cp .env.example .env # 2. 构建并启动 docker compose up -d --build # 3. 查看日志 docker compose logs -f # 4. 停止服务 docker compose down ``` 默认端口:8000 ### 环境变量参数说明 | 参数名 | 必填 | 说明 | 获取方式 | |--------|------|------|----------| | `CLIENT_ID` | 是 | Entra 应用客户端 ID | Azure AD 应用注册概览页 | | `TENANT_ID` | 是 | 租户 ID | Azure AD 应用注册概览页 | | `CLIENT_SECRET` | 是 | 应用客户端密钥 | Azure AD -> 证书和密码 | | `DEFAULT_PASSWORD` | 是 | 新建账号默认密码 | 自定义高强度密码 | | `DEFAULT_DOMAIN` | 建议 | 默认域名 | 例如 `yourtenant.onmicrosoft.com` | | `DEFAULT_LICENSE_SKU` | 可选 | 默认许可证 SKU | 例如 `ENTERPRISEPACK`、`M365_BUSINESS_PREMIUM` | | `LICENSE_ASSIGNMENT_REQUIRED` | 可选 | 许可证分配失败时是否回滚删除新账号 | 默认 `false` | | `DEFAULT_USAGE_LOCATION` | 建议 | 默认使用地区 | 国际版常用:`US`、`SG`、`JP` | | `WEB_AUTH_ENABLED` | 可选 | 后台登录保护 | `true` 或 `false` | | `ADMIN_USERNAME` | 建议 | 后台登录用户名 | 自定义 | | `ADMIN_PASSWORD` | 建议 | 后台登录密码 | 自定义 | | `YAOHUO_VERIFICATION_ENABLED` | 可选 | 是否启用妖火论坛私信验证免兑换码开通 | `true` 或 `false` | | `YAOHUO_COOKIE` | 妖火验证必填 | 后台已登录妖火账号的 Cookie | 浏览器复制完整 Cookie | | `YAOHUO_MESSAGE_URL` | 可选 | 妖火发私信地址 | 默认 `https://www.yaohuo.me/bbs/messagelist_add.aspx` | | `YAOHUO_VERIFICATION_CODE_TTL_SECONDS` | 可选 | 妖火验证码有效期(秒) | 默认 `600` | | `SESSION_SECRET` | 建议 | Flask 会话密钥 | 随机长字符串 | | `HOST` | 可选 | 服务监听地址 | 默认 `0.0.0.0` | | `PORT` | 可选 | 服务监听端口 | 默认 `8000` | | `DEBUG` | 可选 | 调试模式 | 默认 `false` | 提示:如果本地误用了容器内的 SQLite 路径(例如 `sqlite:////app/data/redemption.db`),项目现在会自动映射到当前仓库下的对应本地路径。 ### Entra ID (Azure AD) 应用配置 1. **创建应用注册** - 登录 Microsoft Entra 管理中心 - 导航到 `身份` -> `应用注册` -> `+ 新建注册` - 填写名称(例如 `Office 365 Self Service`) - 选择「仅此组织目录中的帐户」 - 不需要填写重定向 URI - 点击「注册」 2. **获取应用信息** - 复制「应用程序(客户端) ID」→ `CLIENT_ID` - 复制「目录(租户) ID」→ `TENANT_ID` 3. **创建客户端密钥** - 导航到「证书和密码」 - 点击「+ 新建客户端密码」 - 设置描述和过期时间 - 点击「添加」后复制密钥值 → `CLIENT_SECRET` 4. **配置 API 权限** - 导航到「API 权限」 - 点击「+ 添加权限」-> 「Microsoft Graph」-> 「应用程序权限」 - 添加以下权限: - `User.ReadWrite.All` - 读取和写入用户 - `User-PasswordProfile.ReadWrite.All` - 密码配置 - `LicenseAssignment.ReadWrite.All` - 许可证分配 - 点击「为 xx 授予管理员同意」 ## 使用说明 ### 管理员后台 访问地址:`http://ip:port/admin/` 1. 使用设置的 admin 账号登录 2. 点击「生成兑换码」批量生成兑换码 3. 可以查看兑换码、兑换记录和审计日志 ### 用户自助开通 访问地址:`http://ip:port/` 1. 输入管理员提供的兑换码 2. 输入想要的用户名(不需要加域名) 3. 点击「立即开通」 4. 系统返回临时密码,首次登录后需更改密码 ### 妖火论坛验证开通 1. 在 `.env` 中启用 `YAOHUO_VERIFICATION_ENABLED=true` 2. 配置可用的 `YAOHUO_COOKIE` 3. 用户在首页切换到「妖火验证开通」 4. 输入目标妖火 ID,系统向该 ID 发送私信验证码 5. 对方提供验证码后完成验证 6. 验证通过后无需兑换码即可直接开通账号 ## 技术栈 - Python 3.9+ - Flask + Flask-SQLAlchemy - Microsoft Graph API - SQLite(数据持久化) - Docker ## 注意事项 - `DEFAULT_LICENSE_SKU` 必须是租户中实际存在的 SKU 名称 - 如果希望“建号和授权”保持强一致,可设置 `LICENSE_ASSIGNMENT_REQUIRED=true` - 兑换码使用后立即失效,无法重复使用 - 生产环境建议使用 `DEBUG=false` 并配置反向代理