# Office 365 Web 管理平台 基于你指定的 [`eggyrooch-blip/office365-tools`](https://github.com/eggyrooch-blip/office365-tools) 思路重新封装,做成了一套可直接 Web 管理的 Office 365 / Microsoft 365 账号管理后台。当前项目只保留国际版 Microsoft 365 / Microsoft Graph 实现。 当前版本覆盖的核心能力: - 单个账号增删改查 - 用户列表勾选后批量删除、批量启用、批量停用、批量重置密码 - 批量创建、批量更新、批量删除 - 单个与批量重置密码 - 批量模板 CSV 下载后上传执行 - 批量任务进度展示,详细处理过程写入日志文件 - 许可证 SKU 列表与剩余席位查看 - 基于 `.env` 的租户配置 - 可选的后台登录保护 ## 项目结构 ```text . ├── app.py ├── office365_admin/ │ ├── __init__.py │ ├── batch.py │ ├── graph.py │ ├── routes.py │ ├── services.py │ ├── settings.py │ ├── static/ │ └── templates/ ├── tests/ └── reference-office365-tools/ # 参考仓库,保留用于对照 ``` ## 启动方式 1. 创建虚拟环境并安装依赖 ```bash python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` 2. 复制配置文件 ```bash cp .env.example .env ``` 3. 在 `.env` 中填写你的租户配置 必填项: - `CLIENT_ID` - `TENANT_ID` - `CLIENT_SECRET` - `DEFAULT_PASSWORD` 常用项: - `DEFAULT_DOMAIN` - `DEFAULT_LICENSE_SKU` - `ADMIN_USERNAME` - `ADMIN_PASSWORD` 4. 启动服务 ```bash python3 app.py ``` 默认访问地址: - [http://127.0.0.1:8000](http://127.0.0.1:8000) ## Docker Compose 部署 项目已经提供: - [Dockerfile](/Users/youbin/Desktop/Office365UserManage/Dockerfile) - [docker-compose.yml](/Users/youbin/Desktop/Office365UserManage/docker-compose.yml) - [.dockerignore](/Users/youbin/Desktop/Office365UserManage/.dockerignore) 部署前提: - 服务器或本机已安装 Docker Engine - 已安装 Docker Compose 插件,确保 `docker compose version` 可以正常执行 部署步骤: 1. 先准备好本地 `.env` ```bash cp .env.example .env ``` 必填项至少包括: - `CLIENT_ID` - `TENANT_ID` - `CLIENT_SECRET` - `DEFAULT_PASSWORD` 2. 在项目根目录执行构建并启动 ```bash docker compose up -d --build ``` 3. 查看容器状态 ```bash docker compose ps ``` 4. 查看运行日志 ```bash docker compose logs -f office365manage ``` 5. 停止服务 ```bash docker compose down ``` 说明: - Compose 会读取你本地的 `.env`,但 `.env` 不会被打包进镜像,也不会进入 Git。 - 容器内固定监听 `8000` 端口,并通过 `8000:8000` 映射到宿主机。 - 应用日志会落在宿主机的 `./logs` 目录,便于排查任务执行详情。 - 如果你要改宿主机端口,可以修改 [docker-compose.yml](/Users/youbin/Desktop/Office365UserManage/docker-compose.yml) 中 `ports` 左侧的端口值。 - 如果宿主机的 `8000` 端口已经被本地 `python3 app.py` 等进程占用,请先停止原有服务,或者修改映射端口后再启动 Compose。 ## 批量导入格式 ### 批量创建 CSV ```csv userPrincipalName,displayName,givenName,surname,department,jobTitle,usageLocation,skuPartNumber,password alice,Alice Zhang,Alice,Zhang,Sales,Manager,US,ENTERPRISEPACK,Temp123! bob@contoso.com,Bob Li,Bob,Li,IT,Engineer,US,ENTERPRISEPACK, ``` 说明: - `userPrincipalName` 可以只写用户名,系统会自动拼接 `DEFAULT_DOMAIN` - `password` 为空时使用 `DEFAULT_PASSWORD` - `skuPartNumber` 为空时使用 `DEFAULT_LICENSE_SKU` ### 批量更新 CSV ```csv userPrincipalName,department,jobTitle,accountEnabled,skuPartNumber alice@contoso.com,Operations,Lead,true,O365_BUSINESS bob@contoso.com,Finance,Analyst,false, ``` 说明: - 至少要有一列账号标识 - 批量更新里的空白字段默认忽略,不会清空已有值 ### 批量删除文本 ```text alice bob@contoso.com charlie@contoso.com ``` ### 批量重置密码 CSV ```csv userPrincipalName,password,forceChangePasswordNextSignIn alice@contoso.com,Temp123!,true bob@contoso.com,Another123!,true ``` 也可以直接传纯文本账号列表,此时统一使用 `DEFAULT_PASSWORD`。 ## 配置说明 ### `.env` 参数配置与获取方式 | 参数名 | 是否必填 | 说明 | 获取方式 / 示例 | | --- | --- | --- | --- | | `CLIENT_ID` | 是 | Entra 应用的客户端 ID | 在应用注册概览页复制“应用程序(客户端) ID” | | `TENANT_ID` | 是 | 租户 ID | 在应用注册概览页复制“目录(租户) ID” | | `CLIENT_SECRET` | 是 | 应用客户端密钥值 | 在“证书和密码”中新建客户端密码后复制 `Value` | | `DEFAULT_PASSWORD` | 是 | 新建账号或重置密码时的默认密码 | 由你自行定义,建议使用高强度临时密码 | | `DEFAULT_DOMAIN` | 建议 | 用户名自动补全时使用的默认域名 | 例如 `yourtenant.onmicrosoft.com` 或已验证自定义域名 | | `DEFAULT_USAGE_LOCATION` | 建议 | 账号默认使用地区 | 国际版常见示例:`US`、`SG`、`JP` | | `DEFAULT_LICENSE_SKU` | 可选 | 创建用户时默认分配的许可证 SKU | 例如 `ENTERPRISEPACK`、`M365_BUSINESS_PREMIUM` | | `WEB_AUTH_ENABLED` | 可选 | 是否启用平台网页登录保护 | `true` 或 `false` | | `ADMIN_USERNAME` | 建议 | 本平台网页登录用户名 | 例如 `admin` | | `ADMIN_PASSWORD` | 建议 | 本平台网页登录密码 | 由你自行定义;这不是 Microsoft 365 账号密码 | | `SESSION_SECRET` | 建议 | Flask 会话密钥 | 建议使用随机长字符串 | | `HOST` | 可选 | Web 服务监听地址 | 默认 `0.0.0.0` | | `PORT` | 可选 | Web 服务监听端口 | 默认 `8000` | | `DEBUG` | 可选 | 是否启用调试模式 | 默认 `false` | 说明: - `DEFAULT_LICENSE_SKU` 需要填写租户里实际存在的 SKU Part Number;如果不确定,可以先启动系统,在“许可证概览”里查看。 - `ADMIN_USERNAME` / `ADMIN_PASSWORD` 是这个管理平台自己的登录账号,不是 Microsoft 365 管理员邮箱账号。 - 如果不填写 `DEFAULT_DOMAIN`,创建用户时必须填写完整邮箱格式的 `userPrincipalName`。 ### Entra ID 应用注册配置 在使用本工具之前,需要在 Microsoft Entra ID(Azure AD)中注册应用程序并配置权限。 #### 步骤 1:创建应用注册 1. 登录 Microsoft Entra 管理中心 2. 导航到 `身份` -> `应用注册` 3. 点击 `+ 新建注册` 4. 填写应用信息: - 名称:输入应用名称,例如 `Office 365 用户管理工具` - 支持的帐户类型:选择“仅此组织目录中的帐户” - 重定向 URI:无需填写,本项目使用客户端凭据流程 5. 点击 `注册` #### 步骤 2:获取应用信息 注册完成后,在应用概览页面可以获取: - 应用程序(客户端) ID:复制此值作为 `CLIENT_ID` - 目录(租户) ID:复制此值作为 `TENANT_ID` #### 步骤 3:创建客户端密钥 1. 在应用注册页面,导航到 `证书和密码` 2. 点击 `+ 新建客户端密码` 3. 填写描述和过期时间 4. 点击 `添加` 5. 重要:立即复制密钥值,它只会显示一次;将其填写为 `CLIENT_SECRET` #### 步骤 4:配置 API 权限 1. 在应用注册页面,导航到 `API 权限` 2. 点击 `+ 添加权限` -> `Microsoft Graph` -> `应用程序权限` 必需权限列表: | 权限名称 | 说明 | 是否必需 | | --- | --- | --- | | `User.ReadWrite.All` | 读取和写入所有用户配置文件 | 必需,用于创建、更新、删除用户 | | `User-PasswordProfile.ReadWrite.All` | 读取和写入所有用户的密码配置文件 | 必需,用于重置密码 | | `LicenseAssignment.ReadWrite.All` | 读取和写入所有许可证分配 | 必需,用于分配许可证 | | `Directory.ReadWrite.All` | 读取和写入目录数据 | 可选,更高权限,可替代部分用户写入权限 | | `AuditLog.Read.All` | 读取审核日志数据 | 可选,用于后续扩展登录活动或审计场景 | 权限配置步骤: 1. 搜索并选择每个权限 2. 点击 `添加权限` 3. 添加完成后,点击 `为 [你的组织名称] 授予管理员同意` 4. 确认授予同意 重要提示: - 所有应用程序权限都需要管理员同意才能生效。 - 确保你是该应用程序的 `所有者`。 - 权限生效可能需要几分钟。 - 如果权限 Owner 发生变化,或者管理员重新授予了同意,建议重启本项目服务以重新获取访问令牌。 #### 步骤 5:验证权限配置 在 `API 权限` 页面,确认所有需要的权限状态都显示为“已授予(管理员同意)”。 ### Graph 端点 项目固定使用国际版端点: - Graph API: `https://graph.microsoft.com/v1.0` - Token Endpoint: `https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token` - Scope: `https://graph.microsoft.com/.default` ### 平台登录 如果你希望平台访问前需要登录,请配置: ```env WEB_AUTH_ENABLED=true ADMIN_USERNAME=admin ADMIN_PASSWORD=ChangeMe123! SESSION_SECRET=random-long-secret ``` 如果 `WEB_AUTH_ENABLED=true` 但没有设置用户名密码,系统会自动降级为无登录保护模式,并在页面状态区显示提醒。 ## 测试 ```bash pytest ``` ## 日志 服务运行后会把详细操作日志写入: - [logs/office365_admin.log](/Users/youbin/Desktop/Office365UserManage/logs/office365_admin.log) ## 说明 - `reference-office365-tools` 是我拉下来的参考仓库,当前运行时不会直接引用它。 - Web 平台的 Graph 调用逻辑已经按后台服务方式重构,便于继续扩展审批流、组织架构、日志审计等能力。