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 + + + + + 错误 + + + +
+

登录失败

+

{{.message}}

+ {{.linkText}} +
+ + \ 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 @@