This commit is contained in:
oneao committed 2026-01-13 22:18:01 +08:00
1 parent 6277fb2f9e
commit 8ecac0d7dd
270 files changed
+40438 -529

No files matched your search

@@ -0,0 +1,97 @@
package middleware
import (
"allapp/utils/jwtx"
"allapp/utils/pathx"
"allapp/utils/response"
"context"
"strconv"
"github.com/cloudwego/hertz/pkg/app"
)
// 私有 key,防止冲突
type ctxKeyUser struct{}
// ContextUser 保存用户信息,包括 UserID 和 SpaceID
type ContextUser struct {
UserID int64
SpaceID int64
}
// Auth 中间件,直接在中间件里过滤白名单路径
func Auth() app.HandlerFunc {
whitelistPaths := []string{
"/auth/login",
"/auth/register",
"/auth/refresh/token",
}
return func(ctx context.Context, c *app.RequestContext) {
path := string(c.Request.URI().Path())
if pathx.MatchPath(path, whitelistPaths) {
c.Next(ctx)
return
}
token := string(c.GetHeader("token"))
spaceId := string(c.GetHeader("x-space-id"))
if token == "" {
response.Fail(c).Code(response.HttpCode.Unauthorized).Send()
c.Abort()
return
}
verifyToken := jwtx.VerifyToken(token)
if verifyToken.IsValid {
user := &ContextUser{
UserID: verifyToken.Claims.UserID,
SpaceID: 0,
}
if spaceId != "" {
i, err := strconv.ParseInt(spaceId, 10, 64)
if err != nil {
response.Fail(c).Message("Invalid x-space-id").Send()
c.Abort()
return
}
user.SpaceID = i
}
ctx = setContextUser(ctx, user)
c.Next(ctx)
return
}
response.Fail(c).Code(response.HttpCode.RefreshToken).Send()
c.Abort()
}
}
// GetContextUser 从 context 获取用户信息
func GetContextUser(ctx context.Context) *ContextUser {
user, ok := ctx.Value(ctxKeyUser{}).(*ContextUser)
if !ok || user == nil {
return &ContextUser{}
}
return user
}
// GetUserID 从 context 获取 user_id
func GetUserID(ctx context.Context) int64 {
return GetContextUser(ctx).UserID
}
// GetSpaceID 从 context 获取 space_id,并返回是否有效
func GetSpaceID(ctx context.Context) (int64, bool) {
spaceID := GetContextUser(ctx).SpaceID
return spaceID, spaceID != 0
}
// 内部中间件设置 ContextUser
func setContextUser(ctx context.Context, user *ContextUser) context.Context {
return context.WithValue(ctx, ctxKeyUser{}, user)
}
@@ -0,0 +1,100 @@
package middleware
import (
"allapp/logx"
"allapp/utils/response"
"context"
"fmt"
"go.uber.org/zap"
"runtime/debug"
"strings"
"github.com/cloudwego/hertz/pkg/app"
"github.com/pkg/errors"
)
// ErrorInfo 封装错误信息和调用栈
type ErrorInfo struct {
Message string // 错误信息
FuncName string // 出错函数
File string // 文件路径
Line string // 行号
Stack string // 完整堆栈信息
}
// Error 中间件
func Error() app.HandlerFunc {
return func(ctx context.Context, c *app.RequestContext) {
c.Next(ctx)
if e := c.Errors.Last(); e != nil && e.Err != nil {
info := ParseError(e.Err)
logx.CtxError(ctx, "系统异常",
zap.String("Message", info.Message),
zap.String("File", info.File),
zap.String("Line", info.Line),
zap.String("Func", info.FuncName),
zap.String("Stack", info.Stack),
)
// 返回给前端
response.Fail(c).Message("系统异常,请联系管理员!").Send()
}
}
}
// ParseError 解析 error 为 ErrorInfo
func ParseError(err error) *ErrorInfo {
if err == nil {
return nil
}
info := &ErrorInfo{
Message: err.Error(),
Stack: string(debug.Stack()), // 默认 runtime stack
}
// 尝试解析 pkg/errors stack
type stackTracer interface {
StackTrace() errors.StackTrace
}
if errWithStack, ok := err.(stackTracer); ok {
st := errWithStack.StackTrace()
var funcName, fileLine string
for _, f := range st {
line := fmt.Sprintf("%+v", f)
// 取 biz/ 目录下第一个函数作为业务函数
if strings.Contains(line, "/biz/") {
parts := strings.Split(line, "\n")
if len(parts) >= 2 {
funcName = strings.TrimSpace(parts[0])
fileLine = strings.TrimSpace(parts[1])
} else {
funcName = strings.TrimSpace(line)
fileLine = strings.TrimSpace(line)
}
break
}
}
info.FuncName = funcName
// 分离文件和行号
if idx := strings.LastIndex(fileLine, ":"); idx > 0 {
info.File = fileLine[:idx]
info.Line = fileLine[idx+1:]
} else {
info.File = fileLine
info.Line = ""
}
// 完整堆栈
stackStr := ""
for _, f := range st {
stackStr += fmt.Sprintf("%+v\n", f)
}
info.Stack = stackStr
}
return info
}
@@ -0,0 +1,35 @@
package middleware
import (
"allapp/logx"
"context"
"time"
"github.com/cloudwego/hertz/pkg/app"
"github.com/hertz-contrib/requestid"
"go.uber.org/zap"
)
func Log() app.HandlerFunc {
return func(c context.Context, ctx *app.RequestContext) {
reqId := requestid.Get(ctx)
c = context.WithValue(c, "RequestID", reqId)
start := time.Now() // 记录开始时间
// 执行后续处理
ctx.Next(c)
// 计算耗时
duration := time.Since(start).Milliseconds()
logx.CtxInfo(c, "请求完成",
zap.String("IP", ctx.ClientIP()),
zap.String("Method", string(ctx.Method())),
zap.String("Path", string(ctx.Path())),
zap.Int("Status", ctx.GetResponse().StatusCode()),
zap.Int64("Duration", duration),
)
}
}
@@ -0,0 +1,27 @@
package middleware
import (
"allapp/db"
"allapp/logx"
"context"
"github.com/cloudwego/hertz/pkg/app"
)
func RefreshActive() app.HandlerFunc {
return func(c context.Context, ctx *app.RequestContext) {
// 先执行后续 handler
ctx.Next(c)
userID := GetUserID(c)
if userID == 0 {
return
}
// 异步刷新活跃时间
go func() {
if err := db.Queries.UpdateUserActiveTime(c, userID); err != nil {
logx.CtxError(c, "刷新用户活跃时间失败, userID=%d, err=%v", userID, err)
}
}()
}
}