feat: 引入签名认证、加密工具包及大量goctl代码生成模板,并更新API、Admin和Node服务逻辑。

This commit is contained in:
2026-02-27 08:49:37 -08:00
parent 9dacd85a89
commit e1896f677c
166 changed files with 2913 additions and 489 deletions
+14
View File
@@ -28,3 +28,17 @@ MySQL:
Redis:
Host: 127.0.0.1:6379
Type: node
CacheRedis:
Host: 127.0.0.1:6379
Type: node
AppSignature:
AppSecrets:
android-client: "uB4G,XxL2{7b"
web-client: "uB4G,XxL2{7b"
ios-client: "uB4G,XxL2{7b"
mac-client: "uB4G,XxL2{7b"
ValidWindowSeconds: 300
SkipPrefixes:
- /api/v1/node/health
+15
View File
@@ -32,3 +32,18 @@ Redis:
Host: "${REDIS_HOST}"
Type: node
Pass: "${REDIS_PASS}"
CacheRedis:
Host: "${REDIS_HOST}"
Type: node
Pass: "${REDIS_PASS}"
AppSignature:
AppSecrets:
android-client: "${APP_SECRET}"
web-client: "${APP_SECRET}"
ios-client: "${APP_SECRET}"
mac-client: "${APP_SECRET}"
ValidWindowSeconds: 300
SkipPrefixes:
- /api/v1/node/health
+14
View File
@@ -30,3 +30,17 @@ MySQL:
Redis:
Host: redis:6379
Type: node
CacheRedis:
Host: redis:6379
Type: node
AppSignature:
AppSecrets:
android-client: "uB4G,XxL2{7b"
web-client: "uB4G,XxL2{7b"
ios-client: "uB4G,XxL2{7b"
mac-client: "uB4G,XxL2{7b"
ValidWindowSeconds: 300
SkipPrefixes:
- /api/v1/node/health
+8 -1
View File
@@ -3,8 +3,15 @@
package config
import "github.com/zeromicro/go-zero/rest"
import (
"github.com/zero-ppanel/zero-ppanel/pkg/signature"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/rest"
)
type Config struct {
rest.RestConf
NodeSecret string
CacheRedis redis.RedisConf
AppSignature signature.SignatureConf
}
@@ -8,17 +8,13 @@ import (
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/common"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc"
"github.com/zeromicro/go-zero/rest/httpx"
"github.com/zero-ppanel/zero-ppanel/pkg/result"
)
func HealthHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := common.NewHealthLogic(r.Context(), svcCtx)
resp, err := l.Health()
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
result.HttpResult(r, w, resp, err)
}
}
@@ -8,17 +8,13 @@ import (
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc"
"github.com/zeromicro/go-zero/rest/httpx"
"github.com/zero-ppanel/zero-ppanel/pkg/result"
)
func GetServerConfigHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := node.NewGetServerConfigLogic(r.Context(), svcCtx)
resp, err := l.GetServerConfig()
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
result.HttpResult(r, w, resp, err)
}
}
@@ -8,17 +8,13 @@ import (
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc"
"github.com/zeromicro/go-zero/rest/httpx"
"github.com/zero-ppanel/zero-ppanel/pkg/result"
)
func GetServerUserListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := node.NewGetServerUserListLogic(r.Context(), svcCtx)
resp, err := l.GetServerUserList()
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
result.HttpResult(r, w, resp, err)
}
}
@@ -9,23 +9,19 @@ import (
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/types"
"github.com/zeromicro/go-zero/rest/httpx"
"github.com/zero-ppanel/zero-ppanel/pkg/result"
)
func PushOnlineUsersHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.PushOnlineUsersReq
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
if err := result.Parse(r, &req); err != nil {
result.HttpResult(r, w, nil, err)
return
}
l := node.NewPushOnlineUsersLogic(r.Context(), svcCtx)
err := l.PushOnlineUsers(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.Ok(w)
}
result.HttpResult(r, w, nil, err)
}
}
@@ -9,23 +9,19 @@ import (
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/types"
"github.com/zeromicro/go-zero/rest/httpx"
"github.com/zero-ppanel/zero-ppanel/pkg/result"
)
func PushStatusHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.PushStatusReq
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
if err := result.Parse(r, &req); err != nil {
result.HttpResult(r, w, nil, err)
return
}
l := node.NewPushStatusLogic(r.Context(), svcCtx)
err := l.PushStatus(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.Ok(w)
}
result.HttpResult(r, w, nil, err)
}
}
@@ -9,23 +9,19 @@ import (
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/types"
"github.com/zeromicro/go-zero/rest/httpx"
"github.com/zero-ppanel/zero-ppanel/pkg/result"
)
func PushUserTrafficHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.PushUserTrafficReq
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
if err := result.Parse(r, &req); err != nil {
result.HttpResult(r, w, nil, err)
return
}
l := node.NewPushUserTrafficLogic(r.Context(), svcCtx)
err := l.PushUserTraffic(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.Ok(w)
}
result.HttpResult(r, w, nil, err)
}
}
@@ -0,0 +1,88 @@
package middleware
import (
"bytes"
"io"
"net/http"
"strings"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/config"
"github.com/zero-ppanel/zero-ppanel/pkg/signature"
"github.com/zero-ppanel/zero-ppanel/pkg/xerr"
"github.com/zeromicro/go-zero/rest/httpx"
)
type SignatureMiddleware struct {
conf config.Config
validator *signature.Validator
}
func NewSignatureMiddleware(c config.Config, store signature.NonceStore) *SignatureMiddleware {
return &SignatureMiddleware{
conf: c,
validator: signature.NewValidator(c.AppSignature, store),
}
}
func (m *SignatureMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
appId := r.Header.Get("X-App-Id")
if appId == "" {
next(w, r)
return
}
for _, prefix := range m.conf.AppSignature.SkipPrefixes {
if strings.HasPrefix(r.URL.Path, prefix) {
next(w, r)
return
}
}
timestamp := r.Header.Get("X-Timestamp")
nonce := r.Header.Get("X-Nonce")
sig := r.Header.Get("X-Signature")
if timestamp == "" || nonce == "" || sig == "" {
httpx.WriteJson(w, http.StatusUnauthorized, buildErrResp(xerr.SignatureMissing))
return
}
var bodyBytes []byte
if r.Body != nil {
bodyBytes, _ = io.ReadAll(r.Body)
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}
sts := signature.BuildStringToSign(r.Method, r.URL.Path, r.URL.RawQuery, bodyBytes, appId, timestamp, nonce)
if err := m.validator.Validate(r.Context(), appId, timestamp, nonce, sig, sts); err != nil {
code := mapSignatureErr(err)
httpx.WriteJson(w, http.StatusUnauthorized, buildErrResp(code))
return
}
next(w, r)
}
}
func mapSignatureErr(err error) int {
switch err {
case signature.ErrSignatureMissing:
return xerr.SignatureMissing
case signature.ErrSignatureExpired:
return xerr.SignatureExpired
case signature.ErrSignatureReplay:
return xerr.SignatureReplay
default:
return xerr.SignatureInvalid
}
}
func buildErrResp(code int) map[string]interface{} {
return map[string]interface{}{
"code": code,
"msg": xerr.MapErrMsg(code),
"data": nil,
}
}
+11 -4
View File
@@ -6,17 +6,24 @@ package svc
import (
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/config"
"github.com/zero-ppanel/zero-ppanel/apps/node/internal/middleware"
"github.com/zero-ppanel/zero-ppanel/pkg/signature"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/rest"
)
type ServiceContext struct {
Config config.Config
NodeAuthMiddleware rest.Middleware
Config config.Config
NodeAuthMiddleware rest.Middleware
SignatureMiddleware *middleware.SignatureMiddleware
}
func NewServiceContext(c config.Config) *ServiceContext {
rds := redis.MustNewRedis(c.CacheRedis)
nonceStore := signature.NewRedisNonceStore(rds)
return &ServiceContext{
Config: c,
NodeAuthMiddleware: middleware.NewNodeAuthMiddleware().Handle,
Config: c,
NodeAuthMiddleware: middleware.NewNodeAuthMiddleware().Handle,
SignatureMiddleware: middleware.NewSignatureMiddleware(c, nonceStore),
}
}
+1
View File
@@ -27,6 +27,7 @@ func main() {
defer server.Stop()
ctx := svc.NewServiceContext(c)
server.Use(ctx.SignatureMiddleware.Handle)
handler.RegisterHandlers(server, ctx)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)