feat: LLDAP 用户目录服务初始化

- 基于 lldap/lldap:stable-alpine,Dockerfile 预装 sqlite3
- docker-compose.yml:本地含端口映射 (6178:17170, 3890:3890),生产由 deploy-ai.sh 自动去除
- 支持 env_file 配置,本地与生产环境变量分离
This commit is contained in:
aiyimickey 2026-05-18 14:51:59 +08:00
commit f151b89fa5
8 changed files with 219 additions and 0 deletions

8
.env.example Normal file
View File

@ -0,0 +1,8 @@
# === LLDAP 配置 ===
LLDAP_JWT_SECRET=replace_with_openssl_rand_hex_32
LLDAP_LDAP_USER_PASS=replace_with_admin_password
LLDAP_LDAP_BASE_DN=dc=tlyq,dc=ai
LLDAP_HTTP_PORT=17170
LLDAP_LDAP_PORT=3890
LLDAP_DATABASE_PATH=/data/users.db
LLDAP_ADMIN_PASSWORD=replace_with_admin_password

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.env
data/

15
CHANGELOG.md Normal file
View File

@ -0,0 +1,15 @@
# 变更日志
## 2026-05-14
- [安全] 各站点issue/assets改为运行时通过 `docker exec lldap printenv` 动态获取 admin 密码,不再写入站点 `.env` 文件LLDAP 密码修改后即时生效,无需重新部署
- [新增] 创建 CLAUDE.md、README.md、CHANGELOG.md 项目文档
## 2026-05-12
- [新增] LLDAP 容器安装 sqlite3支持 OA 用户管理页面跨站点查询
## 2026-05-11
- [新增] 从 sso-ai 独立拆出 LLDAP 用户目录服务
- [调整] 域名改为 tlyq.aidc=tlyq,dc=ai

115
CLAUDE.md Normal file
View File

@ -0,0 +1,115 @@
# CLAUDE.md — LLDAP 用户目录服务
## 项目概述
ldap-ai 是基于 [LLDAP](https://github.com/lldap/lldap) 的轻量级 LDAP 用户目录服务,域名为内部服务(不对外暴露)。为 OA 统一门户、工单系统、资产管理系统提供统一的 LDAP 用户认证。`dc=tlyq,dc=ai`。
---
## 快速参考
| 属性 | 值 |
|------|-----|
| 用途 | 统一用户目录LDAP 认证) |
| 服务器 | txjpIP: 43.133.38.210 |
| 代码路径 | `/root/docker/ldap-ai/` |
| 容器名 | `lldap` |
| 镜像 | `lldap/lldap:stable-alpine` |
| LDAP Base DN | `dc=tlyq,dc=ai` |
| 本地端口 | 6178Web UI/ 3890LDAP |
| 默认管理员 | `admin` / `admin123` |
| 数据目录 | `data/lldap/`(宿主机挂载) |
---
## 关键文件
| 文件 | 职责 |
|------|------|
| `docker-compose.yml` | 生产部署(共用 webnet不暴露端口 |
| `docker-compose.local.yml` | 本地开发(暴露 6178 + 3890 端口) |
| `.env` | 环境变量JWT secret、admin 密码、LDAP 端口等) |
| `.env.example` | 环境变量模板 |
| `data/lldap/` | LLDAP 持久化数据SQLite 用户数据库) |
---
## 环境变量
| 变量 | 说明 |
|------|------|
| `LLDAP_JWT_SECRET` | LLDAP JWT 签名密钥 |
| `LLDAP_ADMIN_PASSWORD` | LLDAP admin 用户的 LDAP 密码(也是 Web UI 登录密码) |
| `LLDAP_LDAP_USER_PASS` | LDAP 只读用户的绑定密码(供应用 bind 用) |
| `LLDAP_LDAP_BASE_DN` | LDAP Base DN`dc=tlyq,dc=ai` |
| `LLDAP_HTTP_PORT` | Web UI 端口(容器内 17170 |
| `LLDAP_LDAP_PORT` | LDAP 端口(容器内 3890 |
| `LLDAP_DATABASE_PATH` | SQLite 数据库路径 |
---
## Docker 部署
```
txjp 服务器
├── lldap容器 ← LLDAP stable-alpine暴露 :3890
├── oa-ai / assets-ai / issue-ai ← 各站点直连 lldap:3890 做 LDAP 认证
└── webnetexternal ← 共享网络
```
**启动**
```bash
# 本地开发
cd ldap-ai
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d
# 云服务器
ssh txjp "cd /root/docker/ldap-ai && docker compose up -d"
```
**Web UI**`http://localhost:6178`admin / admin123
---
## 认证机制
各站点OA/assets/issue直连 LLDAP 进行 LDAP bind 认证:
1. **ldapAuth(username, password)**:用户 DN bind 验证 → 成功返回用户信息
2. **ldapUserExists(username)**:用 admin 凭据搜索用户是否存在Q1 安全需求:已删除用户需强制退出)
3. **LDAP 密码管理**OA 通过 `docker exec lldap lldap_set_password` 修改密码
---
## 开发规范
- **新增用户**:通过 OA 用户管理页面创建,底层调用 LLDAP API
- **删除用户**OA 标记 LLDAP 用户为 inactive各站点 `ldapUserExists()` 检测到后清除 cookie 踢出
- **改密码**OA 调用 `docker exec lldap` 执行 `lldap_set_password` 脚本
- **LLDAP 故障容错**`ldapUserExists()` 在 LLDAP 不可达时返回 `true`(放行),不阻断正常登录
- **admin 密码**`LLDAP_ADMIN_PASSWORD` 是唯一来源,各站点通过运行时 `docker exec lldap printenv` 动态获取,不写入各站点 `.env`
---
## 服务器操作
```bash
# 重启
ssh txjp "cd /root/docker/ldap-ai && docker compose restart"
# 重建(配置变更后)
ssh txjp "cd /root/docker/ldap-ai && docker compose down && docker compose up -d"
# 安装 sqlite3LLDAP 容器内,用于 OA 用户管理)
ssh txjp "docker exec lldap apk add --no-cache sqlite"
# 查看日志
ssh txjp "docker logs lldap"
```
### 容器重建后
LLDAP 容器重建后OA 容器需能访问 `sqlite3`(用于查询跨站点用户数据)。每次容器重建后需重新安装:
```bash
docker exec lldap apk add --no-cache sqlite
```

2
Dockerfile Normal file
View File

@ -0,0 +1,2 @@
FROM lldap/lldap:stable-alpine
RUN apk add --no-cache sqlite

49
README.md Normal file
View File

@ -0,0 +1,49 @@
# ldap-ai — LLDAP 用户目录服务
基于 [LLDAP](https://github.com/lldap/lldap) 的统一用户目录,为 tlyq.ai 全部站点提供 LDAP 身份认证。
## 快速启动
```bash
cd ldap-ai
# 本地开发(暴露 Web UI :6178 + LDAP :3890
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d
# 云服务器(仅内网,不暴露端口)
docker compose up -d
```
Web UI`http://localhost:6178`admin / admin123
## 目录结构
```
ldap-ai/
├── docker-compose.yml # 生产部署
├── docker-compose.local.yml # 本地开发端口映射
├── .env # 环境变量(不提交)
├── .env.example # 环境变量模板
├── data/lldap/ # 用户数据库(持久化)
├── CLAUDE.md # AI 助手上下文
├── README.md # 本文件
└── CHANGELOG.md # 变更历史
```
## 关联站点
| 站点 | 用途 | LDAP 交互 |
|------|------|-----------|
| `oa-ai` | 统一门户 | 用户登录认证 + 密码修改 + 用户管理 |
| `issue-ai` | 工单系统 | 用户登录认证 + SSO 用户存在性检查 |
| `assets-ai` | 资产管理 | 用户登录认证 + SSO 用户存在性检查 |
## 管理操作
```bash
# 查看数据
docker exec lldap ls /data/
# 备份数据库
cp data/lldap/users.db data/lldap/users.db.bak.$(date +%Y%m%d)
```

5
docker-compose.local.yml Normal file
View File

@ -0,0 +1,5 @@
services:
lldap:
ports:
- "6178:17170" # LLDAP Web UI
- "3890:3890" # LDAP 端口(供本地站点直连)

23
docker-compose.yml Normal file
View File

@ -0,0 +1,23 @@
services:
lldap:
build: .
container_name: lldap
ports:
- "6178:17170"
- "3890:3890"
env_file:
- .env
volumes:
- ./data/lldap:/data
networks:
- webnet
healthcheck:
test: ["CMD-SHELL", "wget -q -O - http://127.0.0.1:17170 || exit 1"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
webnet:
external: true