Files
xfc_server_V2/app/main/api/internal/middleware/authinterceptormiddleware.go
2026-02-04 15:18:37 +08:00

96 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package middleware
import (
"context"
"fmt"
"net/http"
"strconv"
"xingfucha-server/app/main/api/internal/config"
"xingfucha-server/app/main/api/internal/types"
"xingfucha-server/app/main/model"
jwtx "xingfucha-server/common/jwt"
"xingfucha-server/common/result"
"xingfucha-server/common/xerr"
"github.com/pkg/errors"
"github.com/redis/go-redis/v9"
"github.com/zeromicro/go-zero/rest/httpx"
)
const (
// 定义错误码
ErrCodeUnauthorized = 401
)
type AuthInterceptorMiddleware struct {
Config config.Config
UserModel model.UserModel
Redis RedisStore
}
func NewAuthInterceptorMiddleware(c config.Config, userModel model.UserModel, redisStore RedisStore) *AuthInterceptorMiddleware {
return &AuthInterceptorMiddleware{
Config: c,
UserModel: userModel,
Redis: redisStore,
}
}
func (m *AuthInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 从请求头中获取Authorization字段
authHeader := r.Header.Get("Authorization")
// 如果没有Authorization头直接放行
if authHeader == "" {
next(w, r)
return
}
// 解析JWT令牌
claims, err := jwtx.ParseJwtToken(authHeader, m.Config.JwtAuth.AccessSecret)
if err != nil {
// JWT解析失败返回401错误
httpx.Error(w, errors.Wrapf(xerr.NewErrCode(ErrCodeUnauthorized), "token解析失败: %v", err))
return
}
// 携带 token 的请求:先查 Redis 封禁缓存,未命中再查库,减少轮询
if m.UserModel != nil && m.Redis != nil && claims.UserId > 0 {
disabled, err := m.isUserDisabled(r.Context(), w, claims.UserId)
if err != nil {
return
}
if disabled {
msg := xerr.MapErrMsg(xerr.USER_DISABLED)
httpx.WriteJson(w, http.StatusOK, result.Error(xerr.USER_DISABLED, msg))
return
}
}
ctx := context.WithValue(r.Context(), jwtx.ExtraKey, claims)
// 使用新的上下文继续处理请求
next(w, r.WithContext(ctx))
}
}
// isUserDisabled 先查 Redis 封禁缓存,未命中再查 DB 并回写缓存
func (m *AuthInterceptorMiddleware) isUserDisabled(ctx context.Context, w http.ResponseWriter, userID int64) (bool, error) {
key := fmt.Sprintf(types.UserDisableCacheKey, userID)
val, err := m.Redis.Get(key)
if err == nil {
return val == "1", nil
}
if err != redis.Nil {
// Redis 异常时降级为查库
}
user, err := m.UserModel.FindOne(ctx, userID)
if err != nil {
return false, nil // 用户不存在时放行,由业务层处理
}
_ = m.Redis.Setex(key, strconv.FormatInt(user.Disable, 10), types.UserDisableCacheTTL)
return user.Disable == model.UserDisableBanned, nil
}