认证: - 图形验证码 GET /auth/captcha(内置 PNG 渲染,零第三方依赖) - 外部用户 OTP 双通道:DB 存储(otp_codes)使邮件与 CLI 共用同一验证码/冷却/失败限速 - 管理员 bcrypt 登录 + 连续失败限速锁定;admin/forgot + admin/reset 邮件重置(SMTP 或日志) - cookie 会话(HttpOnly/SameSite)、me/logout、admin/user 鉴权中间件 用户管理(admin): - CRUD + disable/enable/extend/delete,对接 system 层真实 useradd/usermod/userdel/passwd - system 层三执行模式:dry-run(默认,安全)/ direct(容器/测试用户)/ sudo(生产 sudoers 白名单) - Exists 系统账号一致性检查;deploy/sudoers.example 白名单模板 - 关键操作接入 append-only 审计 其他: - CLI user otp 改 DB store,与邮件通道真正对齐 - 容器镜像补 shadow(alpine 无 useradd);Makefile VERSION 0.2.0-m1 - 测试:auth/service 单测 + api httptest 集成 + 容器内真实系统账号端到端验证
90 lines
3.3 KiB
Makefile
90 lines
3.3 KiB
Makefile
# ws_usernode Makefile —— build / test / dev 工作流
|
||
# 代理:容器构建无法继承 proxychains 注入,通过 --build-arg 显式传递
|
||
# 宿主机代理环境变量(HTTP_PROXY/HTTPS_PROXY/ALL_PROXY/NO_PROXY)。
|
||
|
||
# ---------- 代理参数(供 podman build 使用) ----------
|
||
HTTP_PROXY_ARG := $(if $(HTTP_PROXY),--build-arg HTTP_PROXY=$(HTTP_PROXY),)
|
||
HTTPS_PROXY_ARG := $(if $(HTTPS_PROXY),--build-arg HTTPS_PROXY=$(HTTPS_PROXY),)
|
||
ALL_PROXY_ARG := $(if $(ALL_PROXY),--build-arg ALL_PROXY=$(ALL_PROXY),)
|
||
NO_PROXY_ARG := $(if $(NO_PROXY),--build-arg NO_PROXY=$(NO_PROXY),)
|
||
PROXY_ARGS := $(HTTP_PROXY_ARG) $(HTTPS_PROXY_ARG) $(ALL_PROXY_ARG) $(NO_PROXY_ARG)
|
||
NET_HOST := --network=host
|
||
|
||
GO ?= go
|
||
PODMAN ?= podman
|
||
BIN := bin/usernode
|
||
VERSION ?= 0.2.0-m1
|
||
LDFLAGS := -s -w -X main.version=$(VERSION)
|
||
GOFLAGS := -trimpath
|
||
|
||
# ---------- 后端 ----------
|
||
|
||
.PHONY: build
|
||
build: ## 构建 Go 二进制(后端,不含前端产物)
|
||
$(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BIN) ./cmd/usernode
|
||
|
||
.PHONY: test
|
||
test: ## 运行全部 Go 测试
|
||
$(GO) test ./...
|
||
|
||
.PHONY: vet
|
||
vet: ## 静态检查
|
||
$(GO) vet ./...
|
||
|
||
.PHONY: run
|
||
run: build ## 本地运行(默认 config.toml,缺失则用默认配置)
|
||
./$(BIN) serve
|
||
|
||
.PHONY: migrate
|
||
migrate: build ## 数据库迁移
|
||
./$(BIN) migrate
|
||
|
||
# ---------- 前端 ----------
|
||
|
||
.PHONY: web-install
|
||
web-install: ## 容器内安装前端依赖(node:20-alpine),并初始化 node_modules volume
|
||
$(PODMAN) build $(NET_HOST) $(PROXY_ARGS) -t ws-usernode-web-dev -f web/Containerfile.dev web/
|
||
$(PODMAN) run --rm $(NET_HOST) \
|
||
-v ws_usernode_node_modules:/app/node_modules \
|
||
ws-usernode-web-dev sh -c "ls node_modules >/dev/null && echo node_modules ready"
|
||
|
||
.PHONY: web-dev
|
||
web-dev: ## 前端 dev 容器(热开发,端口 5173;API 代理到 Go 后端)
|
||
$(PODMAN) run --rm -p 5173:5173 \
|
||
-v $(CURDIR)/web:/app \
|
||
-v ws_usernode_node_modules:/app/node_modules \
|
||
-e VITE_API_PROXY=http://host.containers.internal:8080 \
|
||
ws-usernode-web-dev
|
||
|
||
.PHONY: web-build
|
||
web-build: ## 容器内构建前端产物到 web/dist,并复制到 internal/webui/dist(供 go:embed)
|
||
$(PODMAN) build $(NET_HOST) $(PROXY_ARGS) -t ws-usernode-web-dev -f web/Containerfile.dev web/
|
||
$(PODMAN) run --rm $(NET_HOST) \
|
||
-v $(CURDIR)/web:/app \
|
||
-v ws_usernode_node_modules:/app/node_modules \
|
||
-v $(CURDIR)/internal/webui/dist:/embed/dist \
|
||
ws-usernode-web-dev sh -c "npm run build && cp -r dist/. /embed/dist/ && echo web-build ok"
|
||
|
||
# ---------- 镜像 / 分发 ----------
|
||
|
||
.PHONY: image
|
||
image: ## 构建单二进制容器镜像(deploy/Containerfile 多阶段)
|
||
$(PODMAN) build $(NET_HOST) $(PROXY_ARGS) -t ws-usernode:$(VERSION) -t ws-usernode:latest -f deploy/Containerfile .
|
||
|
||
.PHONY: build-embed
|
||
build-embed: web-build ## 构建含前端产物的 Go 二进制(web-build 后重新编译)
|
||
$(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BIN) ./cmd/usernode
|
||
|
||
.PHONY: dev
|
||
dev: ## 开发提示
|
||
@echo "后端:make run 前端:make web-dev"
|
||
@echo "或:go run ./cmd/usernode serve --debug"
|
||
|
||
.PHONY: clean
|
||
clean: ## 清理构建产物
|
||
rm -rf bin web/dist
|
||
|
||
.PHONY: help
|
||
help: ## 显示帮助
|
||
@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}'
|