2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 10:17:17 +08:00

feat: 重构签名算法

This commit is contained in:
2025-05-15 03:19:16 +08:00
parent 00c02e4b16
commit 1adba2da49
9 changed files with 138 additions and 95 deletions

View File

@@ -60,7 +60,7 @@ func Entrance(t *gotext.Locale, conf *koanf.Koanf, session *sessions.Manager) fu
defer render.Release()
render.Status(http.StatusTeapot)
render.JSON(chix.M{
"message": t.Get("invalid request ip: %s", r.RemoteAddr),
"message": t.Get("invalid request ip: %s", ip),
})
return
}

View File

@@ -19,18 +19,20 @@ import (
var ProviderSet = wire.NewSet(NewMiddlewares)
type Middlewares struct {
conf *koanf.Koanf
log *slog.Logger
session *sessions.Manager
app biz.AppRepo
conf *koanf.Koanf
log *slog.Logger
session *sessions.Manager
app biz.AppRepo
userToken biz.UserTokenRepo
}
func NewMiddlewares(conf *koanf.Koanf, log *slog.Logger, session *sessions.Manager, app biz.AppRepo) *Middlewares {
func NewMiddlewares(conf *koanf.Koanf, log *slog.Logger, session *sessions.Manager, app biz.AppRepo, userToken biz.UserTokenRepo) *Middlewares {
return &Middlewares{
conf: conf,
log: log,
session: session,
app: app,
conf: conf,
log: log,
session: session,
app: app,
userToken: userToken,
}
}
@@ -49,7 +51,7 @@ func (r *Middlewares) Globals(t *gotext.Locale, mux *chi.Mux) []func(http.Handle
middleware.Recoverer,
Status(t),
Entrance(t, r.conf, r.session),
MustLogin(t, r.session),
MustLogin(t, r.session, r.userToken),
MustInstall(t, r.app),
}
}

View File

@@ -1,29 +1,24 @@
package middleware
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"fmt"
"io"
"net"
"net/http"
"slices"
"strings"
"time"
"github.com/go-rat/chix"
"github.com/go-rat/sessions"
"github.com/go-rat/utils/str"
"github.com/leonelquinteros/gotext"
"github.com/spf13/cast"
"github.com/tnb-labs/panel/internal/biz"
)
// MustLogin 确保已登录
func MustLogin(t *gotext.Locale, session *sessions.Manager) func(next http.Handler) http.Handler {
func MustLogin(t *gotext.Locale, session *sessions.Manager, userToken biz.UserTokenRepo) func(next http.Handler) http.Handler {
// 白名单
whiteList := []string{
"/api/user/key",
@@ -54,51 +49,16 @@ func MustLogin(t *gotext.Locale, session *sessions.Manager) func(next http.Handl
userID := uint(0)
if r.Header.Get("Authorization") != "" {
signature := strings.TrimPrefix(r.Header.Get("Authorization"), "HMAC-SHA256 ")
// 步骤一:构造规范化请求
body, err := io.ReadAll(r.Body)
if err != nil {
// API 请求验证
if userID, err = userToken.ValidateReq(r); err != nil {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusInternalServerError)
render.Status(http.StatusUnauthorized)
render.JSON(chix.M{
"message": err.Error(),
})
return
}
r.Body = io.NopCloser(bytes.NewReader(body))
canonicalRequest := fmt.Sprintf("%s\n%s\n%s\n%s", r.Method, r.URL.Path, r.URL.Query().Encode(), str.SHA256(string(body)))
// 步骤二:构造待签名字符串
stringToSign := fmt.Sprintf("%s\n%d\n%s", "HMAC-SHA256", cast.ToInt64(r.Header.Get("X-Timestamp")), str.SHA256(canonicalRequest))
// 步骤三:计算签名
validSignature := hmacsha256(stringToSign, cast.ToString(sess.Get("api_secret")))
// 步骤四:验证签名
if subtle.ConstantTimeCompare([]byte(signature), []byte(validSignature)) != 1 {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusUnauthorized)
render.JSON(chix.M{
"message": t.Get("invalid api signature"),
})
return
}
timestamp := cast.ToInt64(r.Header.Get("X-Timestamp"))
if timestamp == 0 || timestamp < (time.Now().Unix()-60) {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusUnauthorized)
render.JSON(chix.M{
"message": t.Get("api signature expired"),
})
return
}
// 步骤五:验证通过
userID = 1
} else {
if sess.Missing("user_id") {
render := chix.NewRender(w)
@@ -144,9 +104,3 @@ func MustLogin(t *gotext.Locale, session *sessions.Manager) func(next http.Handl
})
}
}
func hmacsha256(data string, secret string) string {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}