Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9312c159a2 | ||
|
|
f33dba455c | ||
|
|
d1366e745b | ||
|
|
334af2a02c | ||
|
|
6be442bfde | ||
|
|
9caf09d005 | ||
|
|
d512ec4435 | ||
|
|
f21c0b7be1 | ||
|
|
f7c7aa0d69 | ||
|
|
8bdbd5bdf3 | ||
|
|
f0cacd81e0 | ||
|
|
a9cab340c2 | ||
|
|
fbf3e27aa9 | ||
|
|
13d839cea1 | ||
|
|
4f22296aa1 | ||
|
|
1b5eba34d5 | ||
|
|
0b5dec6965 | ||
|
|
a73662d2de | ||
|
|
d0557f6c73 | ||
|
|
087fef11e0 | ||
|
|
e8871a75b8 | ||
|
|
dbc473067f | ||
|
|
9f8c3559b5 | ||
|
|
50a89b6fc1 | ||
|
|
45db7f75ca | ||
|
|
2db946160d | ||
|
|
f8013278e8 | ||
|
|
fc3749e535 | ||
|
|
c550f395d6 | ||
|
|
9fe26543d2 | ||
|
|
9f9fcd09ae | ||
|
|
8b5f5b72d2 | ||
|
|
3eade23d1d | ||
|
|
c4cac53368 | ||
|
|
ffcd0d6b77 | ||
|
|
e37ec0ec08 | ||
|
|
224f130371 | ||
|
|
26b2bfe649 | ||
|
|
6be18249d8 | ||
|
|
454f704d6d | ||
|
|
45570567d1 | ||
|
|
3f22bee5dd | ||
|
|
d814ad38df | ||
|
|
020b3ef95a | ||
|
|
3c81ecb1e0 | ||
|
|
5e862b04da | ||
|
|
0017eba91d | ||
|
|
75bca05bcb | ||
|
|
b6f9dbcbf6 | ||
|
|
e94bcdc4fa | ||
|
|
b265e2029e | ||
|
|
b1106c1115 | ||
|
|
404503710c | ||
|
|
7617c09af3 | ||
|
|
268867e68a | ||
|
|
d690922508 | ||
|
|
f6c859c05c |
@@ -0,0 +1 @@
|
||||
.git
|
||||
+8
-36
@@ -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 \
|
||||
&& apk add --no-cache git
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||
apk add --no-cache git ca-certificates tzdata
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
ENV GO111MODULE=on
|
||||
ENV GOPROXY=https://goproxy.cn,direct
|
||||
ENV CGO_ENABLED=0
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
package system
|
||||
|
||||
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/os/gtime"
|
||||
commonApi "github.com/tiger1103/gfast/v3/api/v1/common"
|
||||
|
||||
@@ -155,6 +155,11 @@ type IsSuperAdminReq struct {
|
||||
commonApi.Author
|
||||
}
|
||||
|
||||
type IsAdminReq struct {
|
||||
g.Meta `path:"/user/checkIsAdmin" tags:"用户管理" method:"get" summary:"是否是管理员"`
|
||||
commonApi.Author
|
||||
}
|
||||
|
||||
type IsSuperAdminRes struct {
|
||||
g.Meta `mime:"application/json"`
|
||||
IsSuperAdmin bool `json:"isSuperAdmin"`
|
||||
|
||||
@@ -51,12 +51,34 @@ type TenantEditReq struct {
|
||||
TenantType consts.TenantType `p:"tenantType"`
|
||||
CityCode string `p:"cityCode"`
|
||||
BusinessLicense string `p:"businessLicense"`
|
||||
Surplus float64 `p:"surplus"`
|
||||
commonApi.Author
|
||||
}
|
||||
|
||||
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 获取多个租户详情请求参数
|
||||
type GetTenantDetailsByIdsReq struct {
|
||||
g.Meta `path:"/tenant/getTenantDetailsByIds" tags:"租户管理" method:"get" summary:"获取多个租户详情"`
|
||||
|
||||
@@ -3,7 +3,7 @@ module github.com/tiger1103/gfast/v3
|
||||
go 1.26.0
|
||||
|
||||
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/casbin/casbin/v2 v2.42.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/tiger1103/gfast-cache v1.0.11
|
||||
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 (
|
||||
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/fatih/color v1.18.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/stdr v1.2.2 // 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/google/flatbuffers v25.12.19+incompatible // 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/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // 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/serf v0.10.1 // 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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // 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/mapstructure v1.5.0 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // 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/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/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/numcpus v0.6.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
github.com/vcaesar/cedar v0.30.0 // indirect
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // 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.opentelemetry.io/auto/sdk v1.1.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/trace v1.38.0 // 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-20250128144449-3edf0e91c1ae // indirect
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||
golang.org/x/image v0.19.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/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/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
|
||||
google.golang.org/grpc v1.75.0 // indirect
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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.com/red-future/common v0.0.4/go.mod h1:UI9N5UUjilbMPF7+/lypZSnqDVHigt14300oSRrAyZg=
|
||||
gitea.redpowerfuture.com/red-future/common v0.0.29 h1:5McaN5pSewvrLUHQzWMX6EaUvD+B5I5bMYoU+clHJk4=
|
||||
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 v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
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/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
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-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-ego/gse v1.0.2 h1:+27lYFPhQEhA9igtdOsJPRKYL/k3TwYsxBF5jr6KFv4=
|
||||
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.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
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.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
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.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||
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/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
|
||||
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/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/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/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
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.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
||||
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/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
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.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||
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.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
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/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
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/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/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/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=
|
||||
@@ -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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
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.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
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-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s=
|
||||
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/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
||||
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/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/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
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/vcaesar/cedar v0.30.0 h1:9fSDpM7FTjjUdPiBUUa0MWYMRGSEcqgFXvppZcZ4d7Y=
|
||||
github.com/vcaesar/cedar v0.30.0/go.mod h1:lyuGvALuZZDPNXwpzv/9LyxW+8Y6faN7zauFezNsnik=
|
||||
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
|
||||
github.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
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.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-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.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-20250128144449-3edf0e91c1ae h1:COZdc9Ut6wLq7MO9GIYxfZl4n4ScmgqQLoHocKXrxco=
|
||||
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||
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.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
||||
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-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-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-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=
|
||||
@@ -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.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.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
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.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=
|
||||
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.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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
|
||||
@@ -2,6 +2,6 @@ package consts
|
||||
|
||||
const (
|
||||
SuperAdminId = 1 // 超级管理员
|
||||
SalesAgentId = 9 // 销售代理
|
||||
SiteAdminId = 10 // 站点管理员
|
||||
SalesAgentId = 9 // 租户代理管理员
|
||||
SiteAdminId = 10 // 租户普通管理员
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/crypto/gmd5"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
@@ -20,6 +21,7 @@ import (
|
||||
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/service"
|
||||
"github.com/tiger1103/gfast/v3/library/geoallow"
|
||||
"github.com/tiger1103/gfast/v3/library/libUtils"
|
||||
)
|
||||
|
||||
@@ -38,6 +40,21 @@ func (c *loginController) Login(ctx context.Context, req *system.UserLoginReq) (
|
||||
permissions []string
|
||||
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()
|
||||
if !debug {
|
||||
@@ -46,8 +63,6 @@ func (c *loginController) Login(ctx context.Context, req *system.UserLoginReq) (
|
||||
return
|
||||
}
|
||||
}
|
||||
ip := libUtils.GetClientIp(ctx)
|
||||
userAgent := libUtils.GetUserAgent(ctx)
|
||||
user, err = service.SysUser().GetAdminUserByUsernamePassword(ctx, req)
|
||||
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)))
|
||||
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)
|
||||
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 // 城市编码
|
||||
BusinessLicense string // 营业执照
|
||||
TenantSource string // 租户来源
|
||||
Surplus string // 剩余金额
|
||||
}
|
||||
|
||||
// tenantColumns holds the columns for table sys_user.
|
||||
@@ -44,6 +45,7 @@ var tenantColumns = TenantColumns{
|
||||
CityCode: "city_code",
|
||||
BusinessLicense: "business_license",
|
||||
TenantSource: "tenant_source",
|
||||
Surplus: "surplus",
|
||||
}
|
||||
|
||||
// NewTenantDao creates and returns a new DAO object for table data access.
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"gitea.com/red-future/common/http"
|
||||
"gitea.com/red-future/common/utils"
|
||||
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||
"gitea.redpowerfuture.com/red-future/common/http"
|
||||
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
|
||||
@@ -10,8 +10,8 @@ package sysDept
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"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/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
@@ -9,8 +9,8 @@ package sysRole
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
@@ -10,8 +10,9 @@ package sysUser
|
||||
import (
|
||||
"context"
|
||||
"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/database/gdb"
|
||||
"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)
|
||||
liberr.ErrIsNil(ctx, err)
|
||||
liberr.ValueIsNil(user, "账号密码错误")
|
||||
//验证密码复杂度
|
||||
err = s.validatePasswordComplexity(ctx, req.Password)
|
||||
liberr.ErrIsNil(ctx, err)
|
||||
//验证密码
|
||||
if libUtils.EncryptPassword(req.Password, user.UserSalt) != user.UserPassword {
|
||||
liberr.ErrIsNil(ctx, gerror.New("账号密码错误"))
|
||||
@@ -76,6 +80,101 @@ func (s *sSysUser) GetAdminUserByUsernamePassword(ctx context.Context, req *syst
|
||||
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 通过用户名获取用户信息
|
||||
func (s *sSysUser) GetUserByUsername(ctx context.Context, userName string) (user *model.LoginUserRes, err error) {
|
||||
err = g.Try(ctx, func(ctx context.Context) {
|
||||
@@ -782,3 +881,28 @@ func (s *sSysUser) IsSuperAdmin(ctx context.Context, req *system.IsSuperAdminReq
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gitea.com/red-future/common/beans"
|
||||
"gitea.com/red-future/common/minio"
|
||||
"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/database/gdb"
|
||||
"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) {
|
||||
res = new(system.TenantListRes)
|
||||
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)
|
||||
// 根据toke获取用户id
|
||||
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) {
|
||||
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, "修改租户信息失败")
|
||||
})
|
||||
return err
|
||||
|
||||
@@ -23,4 +23,5 @@ type Tenant struct {
|
||||
BusinessLicense interface{} // 营业执照
|
||||
TenantSource interface{} // 租户来源
|
||||
AdminBy interface{} // 管理者
|
||||
Surplus interface{} // 剩余金额
|
||||
}
|
||||
|
||||
@@ -22,4 +22,5 @@ type Tenant struct {
|
||||
BusinessLicense string `json:"businessLicense" description:"营业执照"`
|
||||
TenantSource uint64 `json:"tenantSource" description:"租户来源"`
|
||||
AdminBy uint64 `json:"adminBy" description:"管理者"`
|
||||
Surplus float64 `json:"surplus" description:"剩余金额"`
|
||||
}
|
||||
|
||||
@@ -56,4 +56,10 @@ func (router *Router) BindController(ctx context.Context, group *ghttp.RouterGro
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
// 内部租户余额接口:不挂 gftoken/Auth(model-gateway 内部调用,查/扣租户余额不依赖用户管理员权限)
|
||||
group.Group("/pub", func(group *ghttp.RouterGroup) {
|
||||
group.Bind(
|
||||
controller.TenantBalance,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ type (
|
||||
Delete(ctx context.Context, ids []int) (err error)
|
||||
GetUsers(ctx context.Context, ids []int) (users []*model.SysUserSimpleRes, err error)
|
||||
IsSuperAdmin(ctx context.Context, req *system.IsSuperAdminReq) (isSuperAdmin bool, err error)
|
||||
IsAdmin(ctx context.Context, req *system.IsAdminReq) (isSuperAdmin bool, err error)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
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"
|
||||
"github.com/tiger1103/gfast/v3/library/libRouter"
|
||||
)
|
||||
@@ -22,8 +22,8 @@ type Router struct{}
|
||||
|
||||
func (router *Router) BindController(ctx context.Context, 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)
|
||||
// 绑定后台路由
|
||||
systemRouter.R.BindController(ctx, group)
|
||||
|
||||
@@ -56,6 +56,22 @@ func GetClientIp(ctx context.Context) string {
|
||||
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
|
||||
func GetUserAgent(ctx context.Context) string {
|
||||
return ghttp.RequestFromCtx(ctx).Header.Get("User-Agent")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package main
|
||||
|
||||
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/nosql/redis/v2"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
|
||||
+20
-11
@@ -28,10 +28,10 @@ logger:
|
||||
database:
|
||||
default:
|
||||
- type: "pgsql"
|
||||
host: "116.204.74.41"
|
||||
host: "192.168.0.83"
|
||||
port: "15432"
|
||||
user: "postgres"
|
||||
pass: "123456"
|
||||
user: "sql9f15b63fd203b36e"
|
||||
pass: "1ec94b1acdaf57b66030242d418fad5a"
|
||||
name: "admin"
|
||||
role: "master"
|
||||
maxIdle: "5"
|
||||
@@ -41,10 +41,10 @@ database:
|
||||
debug : true
|
||||
dryRun : false #空跑
|
||||
- type: "pgsql"
|
||||
host: "116.204.74.41"
|
||||
host: "192.168.0.83"
|
||||
port: "15432"
|
||||
user: "postgres"
|
||||
pass: "123456"
|
||||
user: "sql9f15b63fd203b36e"
|
||||
pass: "1ec94b1acdaf57b66030242d418fad5a"
|
||||
name: "admin"
|
||||
role: "slave"
|
||||
maxIdle: "5"
|
||||
@@ -58,18 +58,24 @@ gfToken:
|
||||
timeOut: 10800
|
||||
maxRefresh: 5400
|
||||
multiLogin: true
|
||||
encryptKey: "49c54195e750b04e74a8429b17896586"
|
||||
encryptKey: "5ace42cd685d42cf934ef519ea27f7d7" #49c54195e750b04e74a8429b17896586
|
||||
cacheModel: "redis" #缓存模式 memory OR redis OR dist
|
||||
distPath: "./resource/data/distTokenDb" #使用磁盘缓存时配置数据缓存的目录
|
||||
excludePaths:
|
||||
- "/api/v1/system/login"
|
||||
|
||||
# 登录 IP 地区闸门: 开启后仅允许「中国大陆网段 / 内部·保留地址 / allowIps」的 IP 登录,
|
||||
# 国外 IP 一律拒绝。enabled 置 false 可整体关闭(紧急恢复), 不影响已登录会话。
|
||||
loginIpFilter:
|
||||
enabled: true
|
||||
allowIps: [] # 显式放行 IP(不受地区限制), 如办公网/跳板出口公网 IP
|
||||
denyMsg: "当前网络环境不允许登录"
|
||||
|
||||
# Redis 配置示例
|
||||
redis:
|
||||
# 单实例配置
|
||||
default:
|
||||
address: 116.204.74.41:6379
|
||||
address: 192.168.0.83:6379
|
||||
db: 1
|
||||
idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/1m/1d
|
||||
maxConnLifetime: "90s" #连接最长存活时间,使用时间字符串例如30s/1m/1d
|
||||
@@ -104,8 +110,11 @@ gfcli:
|
||||
noModelComment: true
|
||||
path: "./internal/app/system"
|
||||
|
||||
# 文件上传服务地址,与oss模块minio中的endpoint一致
|
||||
filePrefix: "116.204.74.41:9000"
|
||||
# 文件上传服务地址,与oss模块minio中的endpoint(filePrefix需要加http://)一致
|
||||
filePrefix: "http://192.168.0.83:9000"
|
||||
|
||||
consul:
|
||||
address: 116.204.74.41:8500
|
||||
address: 192.168.0.83:8500
|
||||
|
||||
jaeger: #链路追踪
|
||||
addr: 192.168.0.83:4318
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This shell is executed before docker build.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user