mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 10:17:17 +08:00
feat: 重构签名算法
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user