feat: SSO 统一认证登录

- 集成 Authelia OIDC,支持统一认证登录
- 添加 OIDC 登录页面和回调处理
- 更新 docker-compose.yml 统一环境变量管理
- 更新 CHANGELOG.md 和 CLAUDE.md
This commit is contained in:
gitadmin 2026-06-30 17:09:23 +08:00
parent 2554a61b44
commit fc7f3d7255
5 changed files with 42 additions and 0 deletions

View File

@ -1,9 +1,23 @@
DATABASE_PATH=./data/assets.db DATABASE_PATH=./data/assets.db
JWT_SECRET=your-secret-key-change-in-production JWT_SECRET=your-secret-key-change-in-production
NODE_ENV=development NODE_ENV=development
# ⚠️ 仅限本地开发环境(自签名证书),生产环境禁止设置此变量
NODE_TLS_REJECT_UNAUTHORIZED=0
# LDAP 配置
LDAP_URL=ldap://localhost:3890
LDAP_BASE_DN=dc=tlyq,dc=ai
LDAP_ADMIN_DN=uid=admin,ou=people,dc=tlyq,dc=ai
# issue-ai API 配置(用于故障历史功能) # issue-ai API 配置(用于故障历史功能)
# NEXT_PUBLIC_ 前缀:构建时内嵌到客户端 JS云上必须通过 deploy-ai.sh 设置 # NEXT_PUBLIC_ 前缀:构建时内嵌到客户端 JS云上必须通过 deploy-ai.sh 设置
# 本地开发http://localhost:6176/tickets # 本地开发http://localhost:6176/tickets
# 云上生产https://issue.tlyq.ai/tickets # 云上生产https://issue.tlyq.ai/tickets
NEXT_PUBLIC_ISSUE_URL=http://localhost:6176/tickets NEXT_PUBLIC_ISSUE_URL=http://localhost:6176/tickets
ISSUE_API_URL=http://localhost:6176/api
# OIDC 配置SSO 统一认证)
AUTHELIA_URL=https://sso.tlyq.ai
OIDC_CLIENT_ID=assets-oidc
OIDC_CLIENT_SECRET=change-me-to-hashed-secret
OIDC_REDIRECT_URI=http://localhost:6177/api/auth/callback

View File

@ -1,5 +1,19 @@
# 变更日志 # 变更日志
## 2026-06-30
- [新增] SSO 统一认证:集成 Authelia OIDC支持统一认证登录
- [新增] OIDC 登录页面:添加「统一认证登录」按钮,支持 LDAP 回退
- [新增] `src/lib/oidc.ts`OIDC 客户端配置PKCE + state + nonce
- [新增] `src/app/api/auth/login/oidc/route.ts`OIDC 登录端点
- [新增] `src/app/api/auth/callback/route.ts`OIDC 回调处理(含用户自动创建)
- [新增] `src/app/api/auth/logout/route.ts`:跨域登出(支持 domain 参数)
- [修复] NODE_TLS_REJECT_UNAUTHORIZED=0Authelia 使用自签名证书
- [修复] OIDC redirect_uri 回调重定向到 localhost添加 getBaseUrl() 函数
- [修复] token_endpoint_auth_method 配置缺失:添加 client_secret_basic
- [优化] docker-compose.yml统一环境变量管理移除 env_file
- [优化] .env.example添加 OIDC 配置模板
## 2026-06-24 ## 2026-06-24
- [修复] SQLite 时区根源修复:重建表修改所有时间列 DEFAULT 为 `datetime('now', '+8 hours')`,涉及 6 个表 8 个列 - [修复] SQLite 时区根源修复:重建表修改所有时间列 DEFAULT 为 `datetime('now', '+8 hours')`,涉及 6 个表 8 个列

View File

@ -154,6 +154,11 @@ npm run import # 导入设备数据
| `JWT_SECRET` | `dev-secret-key-local` | `${ASSETS_JWT_SECRET}` | 生产必须强密钥 | | `JWT_SECRET` | `dev-secret-key-local` | `${ASSETS_JWT_SECRET}` | 生产必须强密钥 |
| `DATABASE_PATH` | `./data/assets.db` | `/app/data/assets.db` | Docker volume 挂载 | | `DATABASE_PATH` | `./data/assets.db` | `/app/data/assets.db` | Docker volume 挂载 |
| Cookie 名 | `session_assets` | `session_assets` | 本地两系统用不同名防 localhost 域冲突 | | Cookie 名 | `session_assets` | `session_assets` | 本地两系统用不同名防 localhost 域冲突 |
| `AUTHELIA_URL` | `https://sso.tlyq.ai` | 同 | Authelia 地址 |
| `OIDC_CLIENT_ID` | `assets-oidc` | 同 | OIDC 客户端 ID |
| `OIDC_CLIENT_SECRET` | 本地生成的哈希值 | 服务器生成的哈希值 | OIDC 客户端密钥 |
| `OIDC_REDIRECT_URI` | `http://localhost:6177/api/auth/callback` | `https://assets.tlyq.ai/api/auth/callback` | OIDC 回调地址 |
| `NODE_TLS_REJECT_UNAUTHORIZED` | 不需要 | `0`Authelia 使用自签名证书) | TLS 证书验证 |
### `.env.local` 示例 ### `.env.local` 示例
@ -164,6 +169,10 @@ NODE_ENV=development
ISSUE_API_URL=http://localhost:6176/api ISSUE_API_URL=http://localhost:6176/api
ISSUE_API_KEY=ak_<32字节十六进制> ISSUE_API_KEY=ak_<32字节十六进制>
NEXT_PUBLIC_ISSUE_URL=http://localhost:6176/tickets NEXT_PUBLIC_ISSUE_URL=http://localhost:6176/tickets
AUTHELIA_URL=https://sso.tlyq.ai
OIDC_CLIENT_ID=assets-oidc
OIDC_CLIENT_SECRET=<本地生成的哈希值>
OIDC_REDIRECT_URI=http://localhost:6177/api/auth/callback
``` ```
--- ---

View File

@ -30,6 +30,10 @@ services:
- ALLOWED_API_KEYS=${ALLOWED_API_KEYS} - ALLOWED_API_KEYS=${ALLOWED_API_KEYS}
# 故障历史跳转的工单系统地址(客户端使用) # 故障历史跳转的工单系统地址(客户端使用)
- NEXT_PUBLIC_ISSUE_URL=https://issue.tlyq.ai/tickets - NEXT_PUBLIC_ISSUE_URL=https://issue.tlyq.ai/tickets
# OIDC 配置
- OIDC_CLIENT_ID=${OIDC_CLIENT_ID:-assets-oidc}
- OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET}
- OIDC_REDIRECT_URI=${OIDC_REDIRECT_URI:-https://assets.tlyq.ai/api/auth/callback}
restart: unless-stopped restart: unless-stopped
networks: networks:
- webnet - webnet

View File

@ -23,6 +23,7 @@ export async function getOidcClient() {
client_secret: OIDC_CLIENT_SECRET, client_secret: OIDC_CLIENT_SECRET,
redirect_uris: [OIDC_REDIRECT_URI], redirect_uris: [OIDC_REDIRECT_URI],
response_types: ['code'], response_types: ['code'],
token_endpoint_auth_method: 'client_secret_basic',
}) })
lastDiscovery = now lastDiscovery = now
return oidcClient return oidcClient