From bed3d6d39e326359e83324c24d91674bfcafbcbc Mon Sep 17 00:00:00 2001
From: GuoXun <15140725+Chrysochrome@users.noreply.github.com>
Date: Wed, 27 Aug 2025 14:01:44 +0800
Subject: [PATCH 1/2] Remove search section from index.html
---
web/templates/index/index.html | 27 ---------------------------
1 file changed, 27 deletions(-)
diff --git a/web/templates/index/index.html b/web/templates/index/index.html
index 185b47e..d09334b 100755
--- a/web/templates/index/index.html
+++ b/web/templates/index/index.html
@@ -135,33 +135,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
选择您的默认搜索引擎:
-
- 搜索热词:
-
-
-
-
-
-
-
{{ range .CategorySites }}
{{ if .SiteList }}
From d3fb9aa20b8f52c4ca234e80abeff330b8351f4c Mon Sep 17 00:00:00 2001
From: henrylinux
Date: Wed, 29 Oct 2025 15:04:07 +0800
Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=A3=9E?=
=?UTF-8?q?=E4=B9=A6SSO=E7=99=BB=E5=BD=95=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增飞书OAuth 2.0认证功能
- 首页访问控制:需要飞书登录才能访问
- 管理后台独立认证:不受飞书登录影响
- 环境变量配置支持:支持K8s部署
- Docker容器化支持
- 新增相关文档和配置文件
主要变更:
- 新增 internal/service/auth/ 飞书认证服务
- 新增 internal/handler/auth/ 认证处理器
- 新增 internal/middleware/index_auth.go 首页认证中间件
- 更新 config/prod.yml 支持环境变量配置
- 更新 internal/server/http.go 注册认证路由
- 新增 Dockerfile.simple 和 docker-compose.yml
- 新增部署文档 DOCKER_DEPLOY.md 和 FEISHU_CONFIG.md
---
DOCKER_DEPLOY.md | 227 ++++++++++++++++++
Dockerfile | 6 +
Dockerfile.simple | 37 +++
FEISHU_CONFIG.md | 78 ++++++
cmd/server/wire/wire.go | 2 +
cmd/server/wire/wire_gen.go | 6 +-
config/prod.yml | 10 +
data/storage/webstack-go.db | Bin 0 -> 40960 bytes
docker-compose.yml | 26 ++
go.mod | 18 +-
go.sum | 28 +--
internal/handler/auth/handler.go | 96 ++++++++
internal/middleware/index_auth.go | 52 ++++
internal/middleware/jwt.go | 2 +-
internal/server/http.go | 19 +-
internal/service/auth/feishu.go | 184 ++++++++++++++
internal/service/auth/service.go | 79 ++++++
pkg/config/config.go | 20 ++
start.sh | 11 +
storage/webstack-go.db | Bin 0 -> 45056 bytes
.../fonts/materialdesignicons-webfont.eot | Bin 700272 -> 700139 bytes
.../fonts/materialdesignicons-webfont.ttf | Bin 700052 -> 699919 bytes
.../fonts/materialdesignicons-webfont.woff | Bin 336356 -> 336348 bytes
.../fonts/materialdesignicons-webfont.woff2 | Bin 235176 -> 235174 bytes
.../fonts/fontawesome/fonts/FontAwesome.otf | Bin 85908 -> 85904 bytes
.../fontawesome/fonts/fontawesome-webfont.eot | Bin 56006 -> 56004 bytes
.../fontawesome/fonts/fontawesome-webfont.ttf | Bin 112160 -> 112142 bytes
.../fonts/fontawesome-webfont.woff | Bin 65452 -> 65451 bytes
web/templates/error.html | 56 +++++
web/templates/index/index.html | 5 +
30 files changed, 932 insertions(+), 30 deletions(-)
create mode 100644 DOCKER_DEPLOY.md
create mode 100644 Dockerfile.simple
create mode 100644 FEISHU_CONFIG.md
create mode 100644 data/storage/webstack-go.db
create mode 100644 docker-compose.yml
create mode 100644 internal/handler/auth/handler.go
create mode 100644 internal/middleware/index_auth.go
create mode 100644 internal/service/auth/feishu.go
create mode 100644 internal/service/auth/service.go
create mode 100755 start.sh
create mode 100644 storage/webstack-go.db
create mode 100644 web/templates/error.html
diff --git a/DOCKER_DEPLOY.md b/DOCKER_DEPLOY.md
new file mode 100644
index 0000000..beadc43
--- /dev/null
+++ b/DOCKER_DEPLOY.md
@@ -0,0 +1,227 @@
+# WebStack-Go Docker 部署指南
+
+## 概述
+
+本项目已成功集成飞书OAuth登录功能,并支持Docker容器化部署。本文档介绍如何使用Docker部署WebStack-Go应用。
+
+## 功能特性
+
+- ✅ 飞书OAuth 2.0登录认证
+- ✅ 首页访问控制(需要飞书登录)
+- ✅ 管理后台独立认证(不受影响)
+- ✅ 环境变量配置支持
+- ✅ Docker容器化部署
+- ✅ Kubernetes部署支持
+
+## 快速开始
+
+### 1. 构建Docker镜像
+
+```bash
+# 编译Linux版本二进制文件
+GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./bin/server-linux ./cmd/server
+
+# 构建Docker镜像
+docker build -f Dockerfile.simple -t webstack-go:latest .
+```
+
+### 2. 运行容器
+
+```bash
+# 使用环境变量运行
+docker run -d \
+ --name webstack-go \
+ -p 8000:8000 \
+ -e FEISHU_APP_ID=your_app_id \
+ -e FEISHU_APP_SECRET=your_app_secret \
+ -e FEISHU_REDIRECT_URL=http://localhost:8000/api/auth/feishu/callback \
+ -e FEISHU_TENANT_KEY=your_tenant_key \
+ webstack-go:latest
+```
+
+### 3. 使用Docker Compose
+
+```bash
+# 修改docker-compose.yml中的环境变量
+# 然后运行
+docker-compose up -d
+```
+
+## 环境变量配置
+
+| 变量名 | 描述 | 示例值 | 必需 |
+|--------|------|--------|------|
+| `FEISHU_APP_ID` | 飞书应用ID | `cli_a8723d9ef275d00e` | ✅ |
+| `FEISHU_APP_SECRET` | 飞书应用密钥 | `gQwAupMXlTaI5dy47DVwLgLNuwIRTUy1` | ✅ |
+| `FEISHU_REDIRECT_URL` | OAuth回调地址 | `http://localhost:8000/api/auth/feishu/callback` | ✅ |
+| `FEISHU_TENANT_KEY` | 企业租户Key | `your_tenant_key` | ❌ |
+
+## 飞书应用配置
+
+### 1. 创建飞书应用
+
+1. 访问 [飞书开放平台](https://open.feishu.cn/)
+2. 创建企业自建应用
+3. 获取 `App ID` 和 `App Secret`
+
+### 2. 配置OAuth重定向URI
+
+在飞书应用管理后台添加以下重定向URI:
+- 开发环境:`http://localhost:8000/api/auth/feishu/callback`
+- 生产环境:`https://yourdomain.com/api/auth/feishu/callback`
+
+### 3. 配置权限
+
+确保应用具有以下权限:
+- `user:read` - 读取用户基本信息
+- `user:read:email` - 读取用户邮箱
+
+## 部署方式
+
+### 方式1:Docker运行
+
+```bash
+# 停止现有容器
+docker stop webstack-go || true
+docker rm webstack-go || true
+
+# 运行新容器
+docker run -d \
+ --name webstack-go \
+ --restart unless-stopped \
+ -p 8000:8000 \
+ -v $(pwd)/storage:/app/storage \
+ -e FEISHU_APP_ID=your_app_id \
+ -e FEISHU_APP_SECRET=your_app_secret \
+ -e FEISHU_REDIRECT_URL=http://yourdomain.com/api/auth/feishu/callback \
+ -e FEISHU_TENANT_KEY=your_tenant_key \
+ webstack-go:latest
+```
+
+### 方式2:Docker Compose
+
+```yaml
+version: '3.8'
+
+services:
+ webstack-go:
+ image: webstack-go:latest
+ container_name: webstack-go
+ restart: unless-stopped
+ ports:
+ - "8000:8000"
+ environment:
+ - FEISHU_APP_ID=your_app_id
+ - FEISHU_APP_SECRET=your_app_secret
+ - FEISHU_REDIRECT_URL=http://yourdomain.com/api/auth/feishu/callback
+ - FEISHU_TENANT_KEY=your_tenant_key
+ volumes:
+ - ./storage:/app/storage
+ healthcheck:
+ test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8000/"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+```
+
+### 方式3:Kubernetes部署
+
+参考 `FEISHU_CONFIG.md` 文件中的Kubernetes配置示例。
+
+## 访问应用
+
+### 1. 首页访问
+
+- 访问 `http://localhost:8000/`
+- 自动重定向到飞书登录页面
+- 完成飞书授权后返回首页
+
+### 2. 管理后台
+
+- 访问 `http://localhost:8000/login`
+- 使用原有的管理员账号登录
+- 不受飞书登录影响
+
+### 3. API文档
+
+- 访问 `http://localhost:8000/swagger/index.html`
+- 查看完整的API文档
+
+## 故障排除
+
+### 1. 容器启动失败
+
+```bash
+# 查看容器日志
+docker logs webstack-go
+
+# 检查容器状态
+docker ps -a | grep webstack
+```
+
+### 2. 飞书登录失败
+
+1. 检查环境变量是否正确设置
+2. 确认飞书应用配置中的重定向URI
+3. 检查网络连接和防火墙设置
+
+### 3. 权限问题
+
+```bash
+# 检查文件权限
+docker exec webstack-go ls -la /app/
+
+# 修复权限
+docker exec webstack-go chmod +x /app/server
+```
+
+## 监控和维护
+
+### 1. 健康检查
+
+```bash
+# 检查应用状态
+curl http://localhost:8000/api/about
+
+# 检查飞书登录
+curl http://localhost:8000/api/auth/feishu/login
+```
+
+### 2. 日志查看
+
+```bash
+# 实时查看日志
+docker logs -f webstack-go
+
+# 查看最近100行日志
+docker logs --tail 100 webstack-go
+```
+
+### 3. 数据备份
+
+```bash
+# 备份数据目录
+docker cp webstack-go:/app/storage ./backup-$(date +%Y%m%d)
+```
+
+## 安全建议
+
+1. **环境变量安全**:使用Kubernetes Secret或Docker Secret管理敏感信息
+2. **网络安全**:配置适当的防火墙规则
+3. **HTTPS**:生产环境建议使用HTTPS
+4. **定期更新**:定期更新Docker镜像和依赖
+
+## 更新日志
+
+- **v1.0.0** - 集成飞书OAuth登录功能
+- **v1.0.1** - 支持环境变量配置
+- **v1.0.2** - 优化Docker镜像构建
+
+## 技术支持
+
+如有问题,请查看:
+1. 项目README.md
+2. 飞书开放平台文档
+3. Docker官方文档
+4. Kubernetes官方文档
diff --git a/Dockerfile b/Dockerfile
index d599109..ee707b6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -24,6 +24,12 @@ RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
ARG APP_ENV
ENV APP_ENV=${APP_ENV}
+# 飞书OAuth环境变量
+ENV FEISHU_APP_ID=""
+ENV FEISHU_APP_SECRET=""
+ENV FEISHU_REDIRECT_URL=""
+ENV FEISHU_TENANT_KEY=""
+
WORKDIR /data/app
COPY --from=builder /data/app/bin /data/app
COPY --from=builder /data/app/web/upload /data/app/web/upload/
diff --git a/Dockerfile.simple b/Dockerfile.simple
new file mode 100644
index 0000000..029e8cb
--- /dev/null
+++ b/Dockerfile.simple
@@ -0,0 +1,37 @@
+FROM alpine:3.18
+
+# 设置时区
+RUN apk add --no-cache tzdata && \
+ cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
+ echo "Asia/Shanghai" > /etc/timezone && \
+ apk del tzdata
+
+# 安装必要的运行时依赖
+RUN apk add --no-cache ca-certificates
+
+# 设置工作目录
+WORKDIR /app
+
+# 复制编译好的二进制文件
+COPY bin/server-linux /app/server
+COPY config /app/config
+COPY web /app/web
+
+# 创建必要的目录
+RUN mkdir -p /app/storage
+
+# 设置环境变量
+ENV FEISHU_APP_ID=""
+ENV FEISHU_APP_SECRET=""
+ENV FEISHU_REDIRECT_URL=""
+ENV FEISHU_TENANT_KEY=""
+
+# 暴露端口
+EXPOSE 8000
+
+# 设置可执行权限
+RUN chmod +x /app/server
+
+# 启动命令
+ENTRYPOINT ["/app/server"]
+CMD ["-conf=config/prod.yml"]
diff --git a/FEISHU_CONFIG.md b/FEISHU_CONFIG.md
new file mode 100644
index 0000000..1c96fb8
--- /dev/null
+++ b/FEISHU_CONFIG.md
@@ -0,0 +1,78 @@
+# 飞书OAuth配置环境变量说明
+
+## 环境变量配置
+
+在部署时,需要设置以下环境变量:
+
+```bash
+# 飞书应用配置
+FEISHU_APP_ID=your_app_id
+FEISHU_APP_SECRET=your_app_secret
+FEISHU_REDIRECT_URL=https://your-domain.com/api/auth/feishu/callback
+FEISHU_TENANT_KEY=your_tenant_key # 可选
+```
+
+## K8s部署配置示例
+
+### ConfigMap
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: webstack-config
+data:
+ FEISHU_REDIRECT_URL: "https://your-domain.com/api/auth/feishu/callback"
+ FEISHU_TENANT_KEY: ""
+```
+
+### Secret
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: webstack-secrets
+type: Opaque
+data:
+ FEISHU_APP_ID:
+ FEISHU_APP_SECRET:
+```
+
+### Deployment
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: webstack-go
+spec:
+ template:
+ spec:
+ containers:
+ - name: webstack-go
+ image: webstack-go:latest
+ env:
+ - name: FEISHU_APP_ID
+ valueFrom:
+ secretKeyRef:
+ name: webstack-secrets
+ key: FEISHU_APP_ID
+ - name: FEISHU_APP_SECRET
+ valueFrom:
+ secretKeyRef:
+ name: webstack-secrets
+ key: FEISHU_APP_SECRET
+ envFrom:
+ - configMapRef:
+ name: webstack-config
+```
+
+## 本地开发
+
+创建 `.env` 文件:
+```bash
+FEISHU_APP_ID=cli_a8723d9ef275d00e
+FEISHU_APP_SECRET=gQwAupMXlTaI5dy47DVwLgLNuwIRTUy1
+FEISHU_REDIRECT_URL=http://localhost:8000/api/auth/feishu/callback
+FEISHU_TENANT_KEY=
+```
+
+然后使用 `source .env` 或 `export` 命令设置环境变量。
diff --git a/cmd/server/wire/wire.go b/cmd/server/wire/wire.go
index 179bbde..5f22a2c 100644
--- a/cmd/server/wire/wire.go
+++ b/cmd/server/wire/wire.go
@@ -17,6 +17,7 @@ import (
userHandler "github.com/ch3nnn/webstack-go/internal/handler/user"
"github.com/ch3nnn/webstack-go/internal/server"
"github.com/ch3nnn/webstack-go/internal/service"
+ authService "github.com/ch3nnn/webstack-go/internal/service/auth"
categoryService "github.com/ch3nnn/webstack-go/internal/service/category"
configService "github.com/ch3nnn/webstack-go/internal/service/config"
dashboardService "github.com/ch3nnn/webstack-go/internal/service/dashboard"
@@ -58,6 +59,7 @@ var serviceSet = wire.NewSet(
categoryService.NewService,
configService.NewService,
dashboardService.NewService,
+ authService.NewService,
)
var serverSet = wire.NewSet(
diff --git a/cmd/server/wire/wire_gen.go b/cmd/server/wire/wire_gen.go
index 82dc563..8ac3542 100644
--- a/cmd/server/wire/wire_gen.go
+++ b/cmd/server/wire/wire_gen.go
@@ -17,6 +17,7 @@ import (
user2 "github.com/ch3nnn/webstack-go/internal/handler/user"
"github.com/ch3nnn/webstack-go/internal/server"
"github.com/ch3nnn/webstack-go/internal/service"
+ "github.com/ch3nnn/webstack-go/internal/service/auth"
"github.com/ch3nnn/webstack-go/internal/service/category"
"github.com/ch3nnn/webstack-go/internal/service/config"
"github.com/ch3nnn/webstack-go/internal/service/dashboard"
@@ -58,7 +59,8 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
categoryHandler := category2.NewHandler(handlerHandler, categoryService)
configService := config.NewService(serviceService, iSysConfigDao)
configHandler := config2.NewHandler(handlerHandler, configService)
- httpServer := server.NewHTTPServer(engine, logger, viperViper, jwtJWT, dashboardHandler, indexHandler, userHandler, siteHandler, categoryHandler, configHandler)
+ authService := auth.NewService(viperViper, jwtJWT)
+ httpServer := server.NewHTTPServer(engine, logger, viperViper, jwtJWT, dashboardHandler, indexHandler, userHandler, siteHandler, categoryHandler, configHandler, authService)
appApp := newApp(httpServer)
return appApp, func() {
}, nil
@@ -70,7 +72,7 @@ var repositorySet = wire.NewSet(repository.NewDB, repository.NewRepository, repo
var handlerSet = wire.NewSet(handler.NewHandler, user2.NewHandler, index2.NewHandler, site2.NewHandler, category2.NewHandler, dashboard2.NewHandler, config2.NewHandler)
-var serviceSet = wire.NewSet(service.NewService, user.NewService, index.NewService, site.NewService, category.NewService, config.NewService, dashboard.NewService)
+var serviceSet = wire.NewSet(service.NewService, user.NewService, index.NewService, site.NewService, category.NewService, config.NewService, dashboard.NewService, auth.NewService)
var serverSet = wire.NewSet(server.NewHTTPServer)
diff --git a/config/prod.yml b/config/prod.yml
index 48e2b84..c9c6d85 100644
--- a/config/prod.yml
+++ b/config/prod.yml
@@ -19,3 +19,13 @@ log:
max_age: 7
max_size: 1024
compress: true
+
+feishu:
+ app_id: "" # 飞书应用 ID (通过环境变量 FEISHU_APP_ID 设置)
+ app_secret: "" # 飞书应用密钥 (通过环境变量 FEISHU_APP_SECRET 设置)
+ redirect_url: "" # 飞书 OAuth 回调地址 (通过环境变量 FEISHU_REDIRECT_URL 设置)
+ tenant_key: "" # 企业租户 Key (通过环境变量 FEISHU_TENANT_KEY 设置)
+
+auth:
+ cookie_name: "webstack_session" # 会话 Cookie 名称
+ jwt_expire_hours: 168 # JWT 过期时间(小时),默认 7 天
diff --git a/data/storage/webstack-go.db b/data/storage/webstack-go.db
new file mode 100644
index 0000000000000000000000000000000000000000..b104c4345e082a54a4d2c93d544adacfd535ca9f
GIT binary patch
literal 40960
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
dZM2we^JBLtCiuuXZ~c?2t6R5j{cmu8=;3|)
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
X2wV`jAaFt8?+pSM|9@AHTmt?d%6eIK
literal 0
HcmV?d00001
diff --git a/web/static/admin/fonts/materialdesignicons-webfont.eot b/web/static/admin/fonts/materialdesignicons-webfont.eot
index ba6e04ae77b66da721fa38d3afb9b1b882ebcbf4..37dd380b9dbb085cd24d175bce923496a0ca6fc3 100755
GIT binary patch
delta 923
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
E1=F)Dy#N3J
diff --git a/web/static/admin/fonts/materialdesignicons-webfont.woff b/web/static/admin/fonts/materialdesignicons-webfont.woff
index 8fc669b4b7fa28b40e36875df9033545c5012196..c86db3fb09cbb1c5216b9549fc6ea37e2e01a211 100755
GIT binary patch
delta 58
zcmV-A0LB00!xY@Z6tKOkv%afoH?t_?Wd65};Q^*vhcr9_w=_Hh2u-&=i39X@wK4=~
QVYi!M1V16S+kylMpJMPDb^rhX
delta 74
zcmca}SmeoJkqvuSGxBcUyE@YxNU1$e`Nzn+z3U<4vM5I0b^{xx?FKf?9KJv?i%#Y*
aWsJOAbyzYIf!ryHEcS{(`f?Ks=X?NSoEp9W
diff --git a/web/static/admin/fonts/materialdesignicons-webfont.woff2 b/web/static/admin/fonts/materialdesignicons-webfont.woff2
index ceaa60180afe9ac56c24bc4b538f688a74d0495e..444e34c9e580522915d384a144ac8869b7a9c6cd 100755
GIT binary patch
delta 28
kcmZ3nmT%cwz75CPnvb__Ki?aJF2w<~XBYJLC!>V*xG
diff --git a/web/static/index/css/fonts/fontawesome/fonts/FontAwesome.otf b/web/static/index/css/fonts/fontawesome/fonts/FontAwesome.otf
index 81c9ad949b47f64afeca5642ee2494b6e3147f44..fa2e7a45ff0153aa6538345fe10a4d7350770549 100755
GIT binary patch
delta 29
ncmV+&0OJ3Yp9PSg1+XKWvm~7S5tAXVoU^{J6NtCcHUYvI&1?;>
delta 37
rcmbO*pLNQ7)(y&Y7;{hP2C%73v#L#>3$sdDQzEmTdldnbw0y#|cYUD>vl)mzQL|UsOarr|
z+$;&R(dC#%w`wc_#22?OL;-Xkm!x9>D!0#L0saEF&Sn9|1(%g<0Vub=Yyl1sx6OP3
LAPcwdhXFD!<0dU1
delta 139
zcmeBs!?xfJ+lH0CjJ%sy`p)MDQXY}PNZqBjP|>#f7m%o{@L@jATYFAoox*<3A=KeISkT7%Nb?
dEr(G9$X%Di$R_}#_tY>d0Il49r=8JA4*)2CEn)xw
diff --git a/web/static/index/css/fonts/fontawesome/fonts/fontawesome-webfont.woff b/web/static/index/css/fonts/fontawesome/fonts/fontawesome-webfont.woff
index 628b6a52a87e62c6f22426e17c01f6a303aa194e..5d805397b2e3727ee01636314b4022e6bbd31699 100755
GIT binary patch
delta 14
WcmZ4UpLz9v<_$NZHs6f8yaWJ0wg{U5
delta 16
YcmZ4epLxxH<_$NZ7
+
+
+
+
+ 错误
+
+
+
+
+
+
\ No newline at end of file
diff --git a/web/templates/index/index.html b/web/templates/index/index.html
index d09334b..1f77eef 100755
--- a/web/templates/index/index.html
+++ b/web/templates/index/index.html
@@ -126,6 +126,11 @@