Compare commits

57 Commits
Author SHA1 Message Date
19904408334 9312c159a2 feat(login): 增加登录 IP 地区闸门限制
基于 config.yaml 的 loginIpFilter 配置,仅允许中国大陆网段、内部保留地址及 allowIps 中的 IP 登录,拒绝境外 IP,并新增不可伪造的 GetRealClientIP 获取客户端真实 IP。
2026-09-04 17:29:35 +08:00
19904408334 f33dba455c chore(config): 更新数据库连接凭据 2026-09-04 13:28:25 +08:00
19904408334 d1366e745b chore(config): 更新数据库密码 2026-09-02 16:11:38 +08:00
19904408334 334af2a02c chore(config): 更新 encryptKey 配置 2026-09-02 09:52:15 +08:00
19904408334 6be442bfde feat: 新增租户余额内部查询与扣减接口 2026-08-17 17:49:48 +08:00
admin 9caf09d005 gitea,gitea-runner写入docker-compose 2026-08-06 09:40:33 +08:00
19904408334 d512ec4435 feat: 添加租户剩余金额字段及自增更新逻辑 2026-07-01 19:35:39 +08:00
admin f21c0b7be1 common版本更新 2026-06-25 17:05:13 +08:00
admin f7c7aa0d69 common版本回退 2026-06-24 10:53:26 +08:00
admin 8bdbd5bdf3 common版本升级 2026-06-23 18:32:01 +08:00
admin f0cacd81e0 common版本升级 2026-06-23 18:17:41 +08:00
19904408334 a9cab340c2 build: 升级 common 依赖至 v0.0.25 2026-06-23 17:05:54 +08:00
19904408334 fbf3e27aa9 fix: 修复开发环境下验证码校验被跳过的问题 2026-06-23 10:00:56 +08:00
admin 13d839cea1 ci/cd调整 2026-06-10 15:59:10 +08:00
admin 4f22296aa1 ci/cd调整 2026-06-10 15:50:08 +08:00
admin 1b5eba34d5 ci/cd调整 2026-06-10 15:37:11 +08:00
admin 0b5dec6965 ci/cd调整 2026-06-10 10:20:53 +08:00
admin a73662d2de ci/cd调整 2026-06-08 16:59:03 +08:00
admin d0557f6c73 ci/cd调整 2026-06-08 16:54:12 +08:00
admin 087fef11e0 ci/cd调整 2026-06-08 16:43:58 +08:00
admin e8871a75b8 登录增加密码策略校验 2026-06-08 15:36:08 +08:00
admin dbc473067f ci/cd调整 2026-06-08 13:54:25 +08:00
admin 9f8c3559b5 登录增加密码策略校验 2026-06-08 11:37:54 +08:00
19904408334 50a89b6fc1 feat: 添加检查是否为管理员的接口 2026-05-09 10:30:31 +08:00
admin 45db7f75ca common版本更新 2026-04-22 18:00:52 +08:00
admin 2db946160d common版本更新 2026-04-22 18:00:32 +08:00
admin f8013278e8 dockerfile修复 2026-04-22 17:49:35 +08:00
admin fc3749e535 dockerfile修改 2026-04-22 14:54:51 +08:00
admin c550f395d6 dockerfile修改 2026-04-22 14:14:09 +08:00
admin 9fe26543d2 dockerfile修改 2026-04-22 14:13:28 +08:00
admin 9f9fcd09ae dockerfile修改 2026-04-22 13:57:38 +08:00
admin 8b5f5b72d2 dockerfile修改 2026-04-22 13:07:47 +08:00
admin 3eade23d1d 网络环境调整 2026-04-20 20:04:02 +08:00
admin c4cac53368 网络环境调整 2026-04-20 18:42:34 +08:00
admin ffcd0d6b77 网络环境调整 2026-04-20 18:42:07 +08:00
admin e37ec0ec08 网络环境调整 2026-04-13 13:25:38 +08:00
19904408334 224f130371 chore: 移除未使用的配置导入 2026-04-13 09:04:35 +08:00
19904408334 26b2bfe649 chore: 移除未使用的配置导入 2026-04-11 18:40:32 +08:00
admin 6be18249d8 增加dockerfile配置 2026-04-09 17:42:55 +08:00
admin 454f704d6d 增加dockerfile配置 2026-04-09 17:28:08 +08:00
admin 45570567d1 增加dockerfile配置 2026-04-09 16:55:09 +08:00
admin 3f22bee5dd 增加dockerfile配置 2026-04-09 16:10:10 +08:00
admin d814ad38df 增加dockerfile配置 2026-04-09 15:58:04 +08:00
admin 020b3ef95a 增加dockerfile配置 2026-04-09 09:07:12 +08:00
admin 3c81ecb1e0 测试服务器IP配置变更 2026-04-08 22:14:21 +08:00
admin 5e862b04da golang版本升级1.26.0 2026-04-03 11:39:33 +08:00
admin 0017eba91d golang版本升级1.26.0 2026-04-03 11:30:12 +08:00
admin 75bca05bcb golang版本升级1.26.0 2026-04-03 11:05:04 +08:00
19904408334 b6f9dbcbf6 feat: 去掉跨域,在网关统一做跨域处理 2026-04-02 15:17:46 +08:00
19904408334 e94bcdc4fa Merge branch 'dev' of http://116.204.74.41:3000/red-future/admin-go into dev 2026-04-02 15:16:30 +08:00
19904408334 b265e2029e feat: 去掉跨域,在网关统一做跨域处理 2026-04-02 15:16:10 +08:00
admin b1106c1115 Dockerfile 2026-04-01 13:49:14 +08:00
admin 404503710c Dockerfile 2026-04-01 13:04:58 +08:00
admin 7617c09af3 Dockerfile 2026-04-01 11:29:30 +08:00
admin 268867e68a Dockerfile 2026-04-01 11:22:10 +08:00
admin d690922508 Dockerfile 2026-04-01 11:21:44 +08:00
19904408334 f6c859c05c chore: 更新配置文件和依赖引用 2026-03-24 16:13:42 +08:00
26 changed files with 376 additions and 134 deletions
+1
View File
@@ -0,0 +1 @@
.git
+8 -36
View File
@@ -1,52 +1,24 @@
FROM golang:1.25.5-alpine AS builder # 阶段1: 构建
FROM golang:alpine AS builder
# 配置Alpine国内镜像源(加速apk) RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ apk add --no-cache git ca-certificates tzdata
&& apk add --no-cache git
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV GO111MODULE=on ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn,direct ENV GOPROXY=https://goproxy.cn,direct
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
ENV GOTOOLCHAIN=auto ENV GOTOOLCHAIN=auto
ENV GOPRIVATE=gitea.com/red-future/common
# 配置git使用私有Gitea仓库
RUN git config --global url."http://x-token-auth:297685158fb953a1bad6c45e16f72472ca6e9866@116.204.74.41:3000/red-future/common.git".insteadOf "https://gitea.com/red-future/common.git" && \
git config --global credential.helper store
# 设置GIT凭据
RUN echo "http://x-token-auth:297685158fb953a1bad6c45e16f72472ca6e9866@116.204.74.41:3000" > ~/.git-credentials
WORKDIR /build WORKDIR /build
COPY . . COPY . .
RUN go mod tidy && go mod download RUN go mod download && go mod tidy
RUN go build -ldflags="-s -w" -o main ./main.go RUN go build -ldflags="-s -w" -o main ./main.go
FROM alpine:latest
# 配置Alpine国内镜像源(加速apk)
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add --no-cache tzdata \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo Asia/Shanghai > /etc/timezone
ENV TZ=Asia/Shanghai
WORKDIR /app
COPY --from=builder /build/main .
COPY --from=builder /build/manifest/config/config.yaml ./manifest/config/config.yaml
COPY --from=builder /build/resource ./resource
RUN mkdir -p /app/resource/log/run \
&& mkdir -p /app/resource/log/server \
&& adduser -D -u 1000 appuser \
&& chown -R appuser:appuser /app
USER appuser
EXPOSE 8808 EXPOSE 8808
+1 -1
View File
@@ -8,7 +8,7 @@
package system package system
import ( import (
"gitea.com/red-future/common/beans" "gitea.redpowerfuture.com/red-future/common/beans"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
commonApi "github.com/tiger1103/gfast/v3/api/v1/common" commonApi "github.com/tiger1103/gfast/v3/api/v1/common"
+5
View File
@@ -155,6 +155,11 @@ type IsSuperAdminReq struct {
commonApi.Author commonApi.Author
} }
type IsAdminReq struct {
g.Meta `path:"/user/checkIsAdmin" tags:"用户管理" method:"get" summary:"是否是管理员"`
commonApi.Author
}
type IsSuperAdminRes struct { type IsSuperAdminRes struct {
g.Meta `mime:"application/json"` g.Meta `mime:"application/json"`
IsSuperAdmin bool `json:"isSuperAdmin"` IsSuperAdmin bool `json:"isSuperAdmin"`
+22
View File
@@ -51,12 +51,34 @@ type TenantEditReq struct {
TenantType consts.TenantType `p:"tenantType"` TenantType consts.TenantType `p:"tenantType"`
CityCode string `p:"cityCode"` CityCode string `p:"cityCode"`
BusinessLicense string `p:"businessLicense"` BusinessLicense string `p:"businessLicense"`
Surplus float64 `p:"surplus"`
commonApi.Author commonApi.Author
} }
type TenantEditRes struct { type TenantEditRes struct {
} }
// TenantBalanceReq 查询租户余额(内部接口,model-gateway 调用,不走 gftoken/Auth
type TenantBalanceReq struct {
g.Meta `path:"/tenant/balance" tags:"租户余额(内部)" method:"get" summary:"查询租户余额"`
TenantId uint64 `p:"tenantId" v:"required#租户id不能为空"`
}
type TenantBalanceRes struct {
g.Meta `mime:"application/json"`
Tenant *entity.Tenant `json:"tenant"`
}
// TenantDeductReq 扣减租户余额(内部接口,model-gateway 调用;surplus 传负值即扣减)
type TenantDeductReq struct {
g.Meta `path:"/tenant/deduct" tags:"租户余额(内部)" method:"post" summary:"扣减租户余额"`
Id int64 `p:"id" v:"required#租户id不能为空"`
Surplus float64 `p:"surplus"`
}
type TenantDeductRes struct {
}
// GetTenantDetailsByIdsReq 获取多个租户详情请求参数 // GetTenantDetailsByIdsReq 获取多个租户详情请求参数
type GetTenantDetailsByIdsReq struct { type GetTenantDetailsByIdsReq struct {
g.Meta `path:"/tenant/getTenantDetailsByIds" tags:"租户管理" method:"get" summary:"获取多个租户详情"` g.Meta `path:"/tenant/getTenantDetailsByIds" tags:"租户管理" method:"get" summary:"获取多个租户详情"`
+10 -20
View File
@@ -3,7 +3,7 @@ module github.com/tiger1103/gfast/v3
go 1.26.0 go 1.26.0
require ( require (
gitea.com/red-future/common v0.0.4 gitea.redpowerfuture.com/red-future/common v0.0.29
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef
github.com/casbin/casbin/v2 v2.42.0 github.com/casbin/casbin/v2 v2.42.0
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0 github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0
@@ -14,10 +14,9 @@ require (
github.com/shirou/gopsutil/v3 v3.23.2 github.com/shirou/gopsutil/v3 v3.23.2
github.com/tiger1103/gfast-cache v1.0.11 github.com/tiger1103/gfast-cache v1.0.11
github.com/tiger1103/gfast-token v1.0.10 github.com/tiger1103/gfast-token v1.0.10
go.mongodb.org/mongo-driver/v2 v2.4.1
) )
//replace gitea.com/red-future/common v0.0.4 => ../common //replace gitea.redpowerfuture.com/red-future/common v0.0.23 => ../common
require ( require (
github.com/BurntSushi/toml v1.5.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect
@@ -33,7 +32,7 @@ require (
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
github.com/fatih/color v1.18.0 // indirect github.com/fatih/color v1.18.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect github.com/go-ego/gse v1.0.2 // indirect
github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
@@ -49,7 +48,7 @@ require (
github.com/golang/snappy v1.0.0 // indirect github.com/golang/snappy v1.0.0 // indirect
github.com/google/flatbuffers v25.12.19+incompatible // indirect github.com/google/flatbuffers v25.12.19+incompatible // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
github.com/hashicorp/consul/api v1.26.1 // indirect github.com/hashicorp/consul/api v1.26.1 // indirect
@@ -62,36 +61,28 @@ require (
github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/serf v0.10.1 // indirect github.com/hashicorp/serf v0.10.1 // indirect
github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
github.com/klauspost/crc32 v1.3.0 // indirect
github.com/lib/pq v1.10.9 // indirect github.com/lib/pq v1.10.9 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.10 // indirect github.com/magiconair/properties v1.8.10 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/minio/crc64nvme v1.1.0 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.97 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/olekukonko/errors v1.1.0 // indirect github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.0.9 // indirect github.com/olekukonko/ll v0.0.9 // indirect
github.com/olekukonko/tablewriter v1.1.0 // indirect github.com/olekukonko/tablewriter v1.1.0 // indirect
github.com/philhofer/fwd v1.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/r3labs/diff/v2 v2.15.1 // indirect
github.com/redis/go-redis/v9 v9.12.1 // indirect github.com/redis/go-redis/v9 v9.12.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/tinylib/msgp v1.3.0 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect github.com/tklauser/numcpus v0.6.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/vcaesar/cedar v0.30.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.mongodb.org/mongo-driver/v2 v2.4.1 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect
@@ -101,13 +92,12 @@ require (
go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect
golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae // indirect
golang.org/x/image v0.19.0 // indirect golang.org/x/image v0.19.0 // indirect
golang.org/x/net v0.47.0 // indirect golang.org/x/net v0.47.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.31.0 // indirect golang.org/x/text v0.31.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
google.golang.org/grpc v1.75.0 // indirect google.golang.org/grpc v1.75.0 // indirect
+21 -36
View File
@@ -1,6 +1,6 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
gitea.com/red-future/common v0.0.4 h1:2QgKc+B2iNfPRncKpmIqIzVwaMGJ3y3dt5v+35YD8SU= gitea.redpowerfuture.com/red-future/common v0.0.29 h1:5McaN5pSewvrLUHQzWMX6EaUvD+B5I5bMYoU+clHJk4=
gitea.com/red-future/common v0.0.4/go.mod h1:UI9N5UUjilbMPF7+/lypZSnqDVHigt14300oSRrAyZg= gitea.redpowerfuture.com/red-future/common v0.0.29/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
@@ -69,8 +69,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ego/gse v1.0.2 h1:+27lYFPhQEhA9igtdOsJPRKYL/k3TwYsxBF5jr6KFv4=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-ego/gse v1.0.2/go.mod h1:Fy35G+q7VV7Et1zIKO8o/sW1kkugV3znXap/lF/11zc=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@@ -143,8 +143,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
@@ -200,11 +200,6 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM=
github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -241,12 +236,6 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
github.com/minio/crc64nvme v1.1.0 h1:e/tAguZ+4cw32D+IO/8GSf5UVr9y+3eJcxZI2WOO/7Q=
github.com/minio/crc64nvme v1.1.0/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.97 h1:lqhREPyfgHTB/ciX8k2r8k0D93WaFqxbJX36UZq5occ=
github.com/minio/minio-go/v7 v7.0.97/go.mod h1:re5VXuo0pwEtoNLsNuSr0RrLfT/MBtohwdaSmPPSRSk=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -271,8 +260,6 @@ github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfB
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -296,6 +283,8 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg=
github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc=
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg= github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@@ -303,8 +292,6 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@@ -320,6 +307,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -331,21 +319,17 @@ github.com/tiger1103/gfast-cache v1.0.11 h1:Y2DEGfFSfMnpZVDnB3fYrgst4OPjRqW2aZfZ
github.com/tiger1103/gfast-cache v1.0.11/go.mod h1:w78YRlmzYdYfibgSwYG2P9yfot8FMSS9d6OZ7cGyCNs= github.com/tiger1103/gfast-cache v1.0.11/go.mod h1:w78YRlmzYdYfibgSwYG2P9yfot8FMSS9d6OZ7cGyCNs=
github.com/tiger1103/gfast-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s= github.com/tiger1103/gfast-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s=
github.com/tiger1103/gfast-token v1.0.10/go.mod h1:a/21mxmj7zFeNvjhZSC0XpEAFHfb1aT2k6DXnufFU1s= github.com/tiger1103/gfast-token v1.0.10/go.mod h1:a/21mxmj7zFeNvjhZSC0XpEAFHfb1aT2k6DXnufFU1s=
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/vcaesar/cedar v0.30.0 h1:9fSDpM7FTjjUdPiBUUa0MWYMRGSEcqgFXvppZcZ4d7Y=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/vcaesar/cedar v0.30.0/go.mod h1:lyuGvALuZZDPNXwpzv/9LyxW+8Y6faN7zauFezNsnik=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -382,11 +366,9 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae h1:COZdc9Ut6wLq7MO9GIYxfZl4n4ScmgqQLoHocKXrxco= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ= golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys= golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
@@ -406,6 +388,7 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -473,7 +456,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
@@ -501,6 +483,9 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+2 -2
View File
@@ -2,6 +2,6 @@ package consts
const ( const (
SuperAdminId = 1 // 超级管理员 SuperAdminId = 1 // 超级管理员
SalesAgentId = 9 // 销售代理 SalesAgentId = 9 // 租户代理管理员
SiteAdminId = 10 // 站点管理员 SiteAdminId = 10 // 租户普通管理员
) )
+41 -2
View File
@@ -9,6 +9,7 @@ package controller
import ( import (
"context" "context"
"strings"
"github.com/gogf/gf/v2/crypto/gmd5" "github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
@@ -20,6 +21,7 @@ import (
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service" commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/model" "github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/service" "github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/geoallow"
"github.com/tiger1103/gfast/v3/library/libUtils" "github.com/tiger1103/gfast/v3/library/libUtils"
) )
@@ -38,6 +40,21 @@ func (c *loginController) Login(ctx context.Context, req *system.UserLoginReq) (
permissions []string permissions []string
menuList []*model.UserMenus menuList []*model.UserMenus
) )
// 登录地区 IP 闸门: 非中国大陆(非内部)地址一律禁止登录。先于验证码/密码校验执行, 失败不泄露账号信息。
ip := libUtils.GetRealClientIP(ctx)
userAgent := libUtils.GetUserAgent(ctx)
if err = loginCheckIPAllow(ctx, ip); err != nil {
// 保存登录失败的日志信息
service.SysLoginLog().Invoke(gctx.New(), &model.LoginLogParams{
Status: 0,
Username: req.Username,
Ip: ip,
UserAgent: userAgent,
Msg: err.Error(),
Module: "系统后台",
})
return
}
//判断验证码是否正确 //判断验证码是否正确
debug := gmode.IsDevelop() debug := gmode.IsDevelop()
if !debug { if !debug {
@@ -46,8 +63,6 @@ func (c *loginController) Login(ctx context.Context, req *system.UserLoginReq) (
return return
} }
} }
ip := libUtils.GetClientIp(ctx)
userAgent := libUtils.GetUserAgent(ctx)
user, err = service.SysUser().GetAdminUserByUsernamePassword(ctx, req) user, err = service.SysUser().GetAdminUserByUsernamePassword(ctx, req)
if err != nil { if err != nil {
// 保存登录失败的日志信息 // 保存登录失败的日志信息
@@ -117,3 +132,27 @@ func (c *loginController) LoginOut(ctx context.Context, req *system.UserLoginOut
err = service.GfToken().RemoveToken(ctx, service.GfToken().GetRequestToken(g.RequestFromCtx(ctx))) err = service.GfToken().RemoveToken(ctx, service.GfToken().GetRequestToken(g.RequestFromCtx(ctx)))
return return
} }
// loginCheckIPAllow 登录地区 IP 闸门判定。
//
// 配置位于 config.yaml 的 loginIpFilter 段:
// - enabled: 总开关, 默认开启; 关闭则一律放行(紧急恢复手段)
// - allowIps: 显式放行 IP 列表(不受地区限制), 如办公网/跳板出口公网 IP
// - denyMsg: 拒绝时返回给前端的文案
//
// 放行条件: 开关关闭 / 命中 allowIps / 内部·保留地址(环回、内网、链路本地等) /
// 中国大陆分配网段。境外及港澳台地址返回拒绝错误。
func loginCheckIPAllow(ctx context.Context, ip string) error {
if !g.Cfg().MustGet(ctx, "loginIpFilter.enabled", true).Bool() {
return nil
}
for _, a := range g.Cfg().MustGet(ctx, "loginIpFilter.allowIps").Strings() {
if strings.TrimSpace(a) == ip {
return nil
}
}
if geoallow.Allow(ip) {
return nil
}
return gerror.New(g.Cfg().MustGet(ctx, "loginIpFilter.denyMsg", "当前网络环境不允许登录").String())
}
@@ -135,3 +135,9 @@ func (c *userController) IsSuperAdmin(ctx context.Context, req *system.IsSuperAd
IsSuperAdminRes.IsSuperAdmin, err = service.SysUser().IsSuperAdmin(ctx, req) IsSuperAdminRes.IsSuperAdmin, err = service.SysUser().IsSuperAdmin(ctx, req)
return return
} }
func (c *userController) IsAdmin(ctx context.Context, req *system.IsAdminReq) (IsSuperAdminRes *system.IsSuperAdminRes, err error) {
IsSuperAdminRes = new(system.IsSuperAdminRes)
IsSuperAdminRes.IsSuperAdmin, err = service.SysUser().IsAdmin(ctx, req)
return
}
@@ -0,0 +1,58 @@
package controller
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
)
var (
TenantBalance = tenantBalanceController{}
)
type tenantBalanceController struct{}
// callerUser 归属校验只取租户字段(调用方经 X-User-Info 头携带用户信息)
type callerUser struct {
TenantId uint64 `json:"tenantId"`
}
// callerTenantId 从 X-User-Info 头解析调用方租户 id;头缺失/解析失败返回 0
func (c *tenantBalanceController) callerTenantId(ctx context.Context) uint64 {
r := g.RequestFromCtx(ctx)
if r == nil {
return 0
}
userInfoHeader := r.Header.Get("X-User-Info")
if userInfoHeader == "" {
return 0
}
var caller callerUser
if err := gconv.Struct(userInfoHeader, &caller); err != nil {
return 0
}
return caller.TenantId
}
// Balance 查询租户余额(内部接口,供 model-gateway 调用;调用方只能查询自己所属租户)
func (c *tenantBalanceController) Balance(ctx context.Context, req *system.TenantBalanceReq) (res *system.TenantBalanceRes, err error) {
if caller := c.callerTenantId(ctx); caller == 0 || caller != req.TenantId {
return nil, gerror.New("无权查询该租户余额")
}
res = new(system.TenantBalanceRes)
res.Tenant, err = service.Tenant().GetTenantDetails(ctx, req.TenantId)
return
}
// Deduct 扣减租户余额(内部接口;surplus 传负值走 Edit 的 Counter 增量即扣减;调用方只能扣减自己所属租户)
func (c *tenantBalanceController) Deduct(ctx context.Context, req *system.TenantDeductReq) (res *system.TenantDeductRes, err error) {
if caller := c.callerTenantId(ctx); caller == 0 || caller != uint64(req.Id) {
return nil, gerror.New("无权扣减该租户余额")
}
err = service.Tenant().Edit(ctx, &system.TenantEditReq{Id: req.Id, Surplus: req.Surplus})
return
}
@@ -30,6 +30,7 @@ type TenantColumns struct {
CityCode string // 城市编码 CityCode string // 城市编码
BusinessLicense string // 营业执照 BusinessLicense string // 营业执照
TenantSource string // 租户来源 TenantSource string // 租户来源
Surplus string // 剩余金额
} }
// tenantColumns holds the columns for table sys_user. // tenantColumns holds the columns for table sys_user.
@@ -44,6 +45,7 @@ var tenantColumns = TenantColumns{
CityCode: "city_code", CityCode: "city_code",
BusinessLicense: "business_license", BusinessLicense: "business_license",
TenantSource: "tenant_source", TenantSource: "tenant_source",
Surplus: "surplus",
} }
// NewTenantDao creates and returns a new DAO object for table data access. // NewTenantDao creates and returns a new DAO object for table data access.
@@ -12,9 +12,9 @@ import (
"fmt" "fmt"
"time" "time"
"gitea.com/red-future/common/beans" "gitea.redpowerfuture.com/red-future/common/beans"
"gitea.com/red-future/common/http" "gitea.redpowerfuture.com/red-future/common/http"
"gitea.com/red-future/common/utils" "gitea.redpowerfuture.com/red-future/common/utils"
"github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
@@ -10,8 +10,8 @@ package sysDept
import ( import (
"context" "context"
"database/sql" "database/sql"
"gitea.com/red-future/common/beans" "gitea.redpowerfuture.com/red-future/common/beans"
"gitea.com/red-future/common/utils" "gitea.redpowerfuture.com/red-future/common/utils"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
@@ -9,8 +9,8 @@ package sysRole
import ( import (
"context" "context"
"gitea.com/red-future/common/beans" "gitea.redpowerfuture.com/red-future/common/beans"
"gitea.com/red-future/common/utils" "gitea.redpowerfuture.com/red-future/common/utils"
"github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
+126 -2
View File
@@ -10,8 +10,9 @@ package sysUser
import ( import (
"context" "context"
"fmt" "fmt"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/utils" "gitea.redpowerfuture.com/red-future/common/beans"
"gitea.redpowerfuture.com/red-future/common/utils"
"github.com/gogf/gf/v2/container/gset" "github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
@@ -64,6 +65,9 @@ func (s *sSysUser) GetAdminUserByUsernamePassword(ctx context.Context, req *syst
user, err = s.GetUserByUsername(ctx, req.Username) user, err = s.GetUserByUsername(ctx, req.Username)
liberr.ErrIsNil(ctx, err) liberr.ErrIsNil(ctx, err)
liberr.ValueIsNil(user, "账号密码错误") liberr.ValueIsNil(user, "账号密码错误")
//验证密码复杂度
err = s.validatePasswordComplexity(ctx, req.Password)
liberr.ErrIsNil(ctx, err)
//验证密码 //验证密码
if libUtils.EncryptPassword(req.Password, user.UserSalt) != user.UserPassword { if libUtils.EncryptPassword(req.Password, user.UserSalt) != user.UserPassword {
liberr.ErrIsNil(ctx, gerror.New("账号密码错误")) liberr.ErrIsNil(ctx, gerror.New("账号密码错误"))
@@ -76,6 +80,101 @@ func (s *sSysUser) GetAdminUserByUsernamePassword(ctx context.Context, req *syst
return return
} }
// validatePasswordComplexity 验证密码复杂度
func (s *sSysUser) validatePasswordComplexity(ctx context.Context, password string) (err error) {
dict, err := commonService.SysDictData().GetDictWithDataByType(ctx, &system.GetDictReq{
DictType: "pass_config",
})
if err != nil || dict == nil || len(dict.Values) == 0 {
// 如果没有配置密码复杂度,则默认放行
return nil
}
config := make(map[string]string)
for _, v := range dict.Values {
config[v.DictValue] = v.Remark
}
// 检查是否启用密码策略
if enabled, ok := config["enabled"]; ok && enabled != "true" {
// 未启用密码策略,直接放行
return nil
}
// 验证最小长度
if minLen, ok := config["min_length"]; ok {
if len(password) < gconv.Int(minLen) {
return gerror.Newf("密码长度不能少于%s位", minLen)
}
}
// 验证最大长度
if maxLen, ok := config["max_length"]; ok {
if len(password) > gconv.Int(maxLen) {
return gerror.Newf("密码长度不能超过%s位", maxLen)
}
}
// 验证是否需要包含数字
if needNumber, ok := config["need_number"]; ok && needNumber == "true" {
hasNumber := false
for _, c := range password {
if c >= '0' && c <= '9' {
hasNumber = true
break
}
}
if !hasNumber {
return gerror.New("密码必须包含数字")
}
}
// 验证是否需要包含小写字母
if needLower, ok := config["need_lower"]; ok && needLower == "true" {
hasLower := false
for _, c := range password {
if c >= 'a' && c <= 'z' {
hasLower = true
break
}
}
if !hasLower {
return gerror.New("密码必须包含小写字母")
}
}
// 验证是否需要包含大写字母
if needUpper, ok := config["need_upper"]; ok && needUpper == "true" {
hasUpper := false
for _, c := range password {
if c >= 'A' && c <= 'Z' {
hasUpper = true
break
}
}
if !hasUpper {
return gerror.New("密码必须包含大写字母")
}
}
// 验证是否需要包含特殊字符
if needSpecial, ok := config["need_special"]; ok && needSpecial == "true" {
hasSpecial := false
specialChars := "!@#$%^&*()_+-=[]{}|;':\",./<>?`~"
for _, c := range password {
if gstr.Contains(specialChars, string(c)) {
hasSpecial = true
break
}
}
if !hasSpecial {
return gerror.New("密码必须包含特殊字符")
}
}
return nil
}
// GetUserByUsername 通过用户名获取用户信息 // GetUserByUsername 通过用户名获取用户信息
func (s *sSysUser) GetUserByUsername(ctx context.Context, userName string) (user *model.LoginUserRes, err error) { func (s *sSysUser) GetUserByUsername(ctx context.Context, userName string) (user *model.LoginUserRes, err error) {
err = g.Try(ctx, func(ctx context.Context) { err = g.Try(ctx, func(ctx context.Context) {
@@ -782,3 +881,28 @@ func (s *sSysUser) IsSuperAdmin(ctx context.Context, req *system.IsSuperAdminReq
} }
return return
} }
func (s *sSysUser) IsAdmin(ctx context.Context, req *system.IsAdminReq) (isSuperAdmin bool, err error) {
_ = req
isSuperAdmin = false
// 获取用户id
getUserInfo, err := utils.GetUserInfo(ctx)
if err != nil {
return
}
userId := getUserInfo.Id
if !g.IsEmpty(userId) {
var roleIds []uint
roleIds, err = service.SysUser().GetAdminRoleIds(ctx, gconv.Uint64(userId))
liberr.ErrIsNil(ctx, err, "获取用户角色失败")
for _, v := range roleIds {
if v == consts.SuperAdminId || v == consts.SiteAdminId {
isSuperAdmin = true
return
} else {
isSuperAdmin = false
}
}
}
return
}
+17 -5
View File
@@ -12,9 +12,9 @@ import (
"database/sql" "database/sql"
"errors" "errors"
"fmt" "fmt"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/minio" "gitea.redpowerfuture.com/red-future/common/beans"
"gitea.com/red-future/common/utils" "gitea.redpowerfuture.com/red-future/common/utils"
"github.com/gogf/gf/v2/container/gset" "github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
@@ -45,7 +45,8 @@ func New() *sTenant {
func (s *sTenant) GetTenantListSearch(ctx context.Context, req *system.TenantListReq) (res *system.TenantListRes, err error) { func (s *sTenant) GetTenantListSearch(ctx context.Context, req *system.TenantListReq) (res *system.TenantListRes, err error) {
res = new(system.TenantListRes) res = new(system.TenantListRes)
err = g.Try(ctx, func(ctx context.Context) { err = g.Try(ctx, func(ctx context.Context) {
res.ImgAddressPrefix = minio.GetFileAddressPrefix(ctx) res.ImgAddressPrefix, err = utils.GetFileAddressPrefix(ctx)
liberr.ErrIsNil(ctx, err, "获取文件地址前缀失败")
model := dao.TenantDao.Ctx(ctx) model := dao.TenantDao.Ctx(ctx)
// 根据toke获取用户id // 根据toke获取用户id
userId := service.Context().GetUserId(ctx) userId := service.Context().GetUserId(ctx)
@@ -257,7 +258,18 @@ func (s *sTenant) Edit(ctx context.Context, req *system.TenantEditReq) (err erro
if !g.IsEmpty(req.TenantType) { if !g.IsEmpty(req.TenantType) {
tenant.TenantType = req.TenantType tenant.TenantType = req.TenantType
} }
_, err = dao.TenantDao.Ctx(ctx).TX(tx).WherePri(req.Id).Update(tenant) _, err = dao.TenantDao.Ctx(ctx).TX(tx).WherePri(req.Id).OmitEmpty().Update(tenant)
// 第二步:单独执行 Surplus 自增/自减(纯Counter,官方标准用法)
if !g.IsEmpty(req.Surplus) {
delta := gconv.Float64(req.Surplus)
_, err = dao.TenantDao.Ctx(ctx).TX(tx).WherePri(req.Id).Data(
dao.TenantDao.Columns().Surplus,
&gdb.Counter{
Field: dao.TenantDao.Columns().Surplus,
Value: delta,
},
).Update()
}
liberr.ErrIsNil(ctx, err, "修改租户信息失败") liberr.ErrIsNil(ctx, err, "修改租户信息失败")
}) })
return err return err
+1
View File
@@ -23,4 +23,5 @@ type Tenant struct {
BusinessLicense interface{} // 营业执照 BusinessLicense interface{} // 营业执照
TenantSource interface{} // 租户来源 TenantSource interface{} // 租户来源
AdminBy interface{} // 管理者 AdminBy interface{} // 管理者
Surplus interface{} // 剩余金额
} }
@@ -22,4 +22,5 @@ type Tenant struct {
BusinessLicense string `json:"businessLicense" description:"营业执照"` BusinessLicense string `json:"businessLicense" description:"营业执照"`
TenantSource uint64 `json:"tenantSource" description:"租户来源"` TenantSource uint64 `json:"tenantSource" description:"租户来源"`
AdminBy uint64 `json:"adminBy" description:"管理者"` AdminBy uint64 `json:"adminBy" description:"管理者"`
Surplus float64 `json:"surplus" description:"剩余金额"`
} }
+6
View File
@@ -56,4 +56,10 @@ func (router *Router) BindController(ctx context.Context, group *ghttp.RouterGro
panic(err) panic(err)
} }
}) })
// 内部租户余额接口:不挂 gftoken/Authmodel-gateway 内部调用,查/扣租户余额不依赖用户管理员权限)
group.Group("/pub", func(group *ghttp.RouterGroup) {
group.Bind(
controller.TenantBalance,
)
})
} }
+1
View File
@@ -49,6 +49,7 @@ type (
Delete(ctx context.Context, ids []int) (err error) Delete(ctx context.Context, ids []int) (err error)
GetUsers(ctx context.Context, ids []int) (users []*model.SysUserSimpleRes, err error) GetUsers(ctx context.Context, ids []int) (users []*model.SysUserSimpleRes, err error)
IsSuperAdmin(ctx context.Context, req *system.IsSuperAdminReq) (isSuperAdmin bool, err error) IsSuperAdmin(ctx context.Context, req *system.IsSuperAdminReq) (isSuperAdmin bool, err error)
IsAdmin(ctx context.Context, req *system.IsAdminReq) (isSuperAdmin bool, err error)
} }
) )
+3 -3
View File
@@ -9,9 +9,9 @@ package router
import ( import (
"context" "context"
"github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/net/ghttp"
commonRouter "github.com/tiger1103/gfast/v3/internal/app/common/router" commonRouter "github.com/tiger1103/gfast/v3/internal/app/common/router"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
systemRouter "github.com/tiger1103/gfast/v3/internal/app/system/router" systemRouter "github.com/tiger1103/gfast/v3/internal/app/system/router"
"github.com/tiger1103/gfast/v3/library/libRouter" "github.com/tiger1103/gfast/v3/library/libRouter"
) )
@@ -22,8 +22,8 @@ type Router struct{}
func (router *Router) BindController(ctx context.Context, group *ghttp.RouterGroup) { func (router *Router) BindController(ctx context.Context, group *ghttp.RouterGroup) {
group.Group("/api/v1", func(group *ghttp.RouterGroup) { group.Group("/api/v1", func(group *ghttp.RouterGroup) {
//跨域处理,安全起见正式环境请注释该行 //跨域处理,安全起见正式环境请注释该行(在网关统一处理跨域问题)
group.Middleware(commonService.Middleware().MiddlewareCORS) //group.Middleware(commonService.Middleware().MiddlewareCORS)
group.Middleware(ghttp.MiddlewareHandlerResponse) group.Middleware(ghttp.MiddlewareHandlerResponse)
// 绑定后台路由 // 绑定后台路由
systemRouter.R.BindController(ctx, group) systemRouter.R.BindController(ctx, group)
+16
View File
@@ -56,6 +56,22 @@ func GetClientIp(ctx context.Context) string {
return g.RequestFromCtx(ctx).GetClientIp() return g.RequestFromCtx(ctx).GetClientIp()
} }
// GetRealClientIP 获取不可伪造的真实客户端IP。
// 优先取 X-Real-IP(部署 nginx 以 $remote_addr 覆盖写入, 客户端无法伪造);
// 否则回退 RemoteAddr(TCP 对端)。
// 不采信 X-Forwarded-For 的首个值: 其采用追加语义, 首段可由客户端注入, 用作
// 登录地区闸门判据时会被伪造绕过。多跳代理部署下须保证最终前置 nginx 不把
// X-Real-IP 覆盖成代理自身地址(单跳时即真实客户端)。
func GetRealClientIP(ctx context.Context) string {
r := g.RequestFromCtx(ctx)
if ip := strings.TrimSpace(r.Header.Get("X-Real-IP")); ip != "" {
if net.ParseIP(ip) != nil {
return ip
}
}
return r.GetRemoteIp()
}
// GetUserAgent 获取user-agent // GetUserAgent 获取user-agent
func GetUserAgent(ctx context.Context) string { func GetUserAgent(ctx context.Context) string {
return ghttp.RequestFromCtx(ctx).Header.Get("User-Agent") return ghttp.RequestFromCtx(ctx).Header.Get("User-Agent")
+1 -1
View File
@@ -1,7 +1,7 @@
package main package main
import ( import (
_ "gitea.com/red-future/common/http" _ "gitea.redpowerfuture.com/red-future/common/http"
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2" _ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
_ "github.com/gogf/gf/contrib/nosql/redis/v2" _ "github.com/gogf/gf/contrib/nosql/redis/v2"
"github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/os/gctx"
+20 -11
View File
@@ -28,10 +28,10 @@ logger:
database: database:
default: default:
- type: "pgsql" - type: "pgsql"
host: "116.204.74.41" host: "192.168.0.83"
port: "15432" port: "15432"
user: "postgres" user: "sql9f15b63fd203b36e"
pass: "123456" pass: "1ec94b1acdaf57b66030242d418fad5a"
name: "admin" name: "admin"
role: "master" role: "master"
maxIdle: "5" maxIdle: "5"
@@ -41,10 +41,10 @@ database:
debug : true debug : true
dryRun : false #空跑 dryRun : false #空跑
- type: "pgsql" - type: "pgsql"
host: "116.204.74.41" host: "192.168.0.83"
port: "15432" port: "15432"
user: "postgres" user: "sql9f15b63fd203b36e"
pass: "123456" pass: "1ec94b1acdaf57b66030242d418fad5a"
name: "admin" name: "admin"
role: "slave" role: "slave"
maxIdle: "5" maxIdle: "5"
@@ -58,18 +58,24 @@ gfToken:
timeOut: 10800 timeOut: 10800
maxRefresh: 5400 maxRefresh: 5400
multiLogin: true multiLogin: true
encryptKey: "49c54195e750b04e74a8429b17896586" encryptKey: "5ace42cd685d42cf934ef519ea27f7d7" #49c54195e750b04e74a8429b17896586
cacheModel: "redis" #缓存模式 memory OR redis OR dist cacheModel: "redis" #缓存模式 memory OR redis OR dist
distPath: "./resource/data/distTokenDb" #使用磁盘缓存时配置数据缓存的目录 distPath: "./resource/data/distTokenDb" #使用磁盘缓存时配置数据缓存的目录
excludePaths: excludePaths:
- "/api/v1/system/login" - "/api/v1/system/login"
# 登录 IP 地区闸门: 开启后仅允许「中国大陆网段 / 内部·保留地址 / allowIps」的 IP 登录,
# 国外 IP 一律拒绝。enabled 置 false 可整体关闭(紧急恢复), 不影响已登录会话。
loginIpFilter:
enabled: true
allowIps: [] # 显式放行 IP(不受地区限制), 如办公网/跳板出口公网 IP
denyMsg: "当前网络环境不允许登录"
# Redis 配置示例 # Redis 配置示例
redis: redis:
# 单实例配置 # 单实例配置
default: default:
address: 116.204.74.41:6379 address: 192.168.0.83:6379
db: 1 db: 1
idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/1m/1d idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/1m/1d
maxConnLifetime: "90s" #连接最长存活时间,使用时间字符串例如30s/1m/1d maxConnLifetime: "90s" #连接最长存活时间,使用时间字符串例如30s/1m/1d
@@ -104,8 +110,11 @@ gfcli:
noModelComment: true noModelComment: true
path: "./internal/app/system" path: "./internal/app/system"
# 文件上传服务地址,与oss模块minio中的endpoint一致 # 文件上传服务地址,与oss模块minio中的endpoint(filePrefix需要加http://)一致
filePrefix: "116.204.74.41:9000" filePrefix: "http://192.168.0.83:9000"
consul: consul:
address: 116.204.74.41:8500 address: 192.168.0.83:8500
jaeger: #链路追踪
addr: 192.168.0.83:4318
-8
View File
@@ -1,8 +0,0 @@
#!/bin/bash
# This shell is executed before docker build.