16844d4a42
- Added AI configuration options to .env.example and config.go for OpenAI integration. - Implemented Redis caching for session management in main.go and auth middleware. - Updated smoke logging service to support real smoking time (`smoke_at`) and AI advice retrieval. - Enhanced API routes to include endpoints for AI advice and unlock functionality for non-members. - Improved database schema with new tables for AI advice and unlock records. - Expanded documentation to cover new AI features and Redis caching implementation.
70 lines
1.9 KiB
Go
70 lines
1.9 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
|
|
rediscache "wx_service/internal/common/redis/cache"
|
|
"wx_service/internal/model"
|
|
)
|
|
|
|
const ContextCurrentUserKey = "currentUser"
|
|
|
|
func AuthMiddleware(db *gorm.DB, sessionCache *rediscache.SessionUserCache) gin.HandlerFunc {
|
|
// AuthMiddleware 是一个 Gin 中间件:
|
|
// - 从 Authorization: Bearer <token> 里取 token
|
|
// - 用 token(这里是 session_key)查用户
|
|
// - (可选) 优先从 Redis 缓存读取,减少每次都访问数据库
|
|
// - 查到后放进 gin.Context,供后面的 handler 使用
|
|
return func(c *gin.Context) {
|
|
token := extractToken(c.GetHeader("Authorization"))
|
|
if token == "" {
|
|
c.AbortWithStatusJSON(http.StatusUnauthorized, model.Error(http.StatusUnauthorized, "missing authorization header"))
|
|
return
|
|
}
|
|
|
|
if sessionCache != nil {
|
|
if cachedUser, ok, err := sessionCache.Get(c.Request.Context(), token); err == nil && ok && cachedUser != nil {
|
|
c.Set(ContextCurrentUserKey, cachedUser)
|
|
c.Next()
|
|
return
|
|
}
|
|
}
|
|
|
|
var user model.User
|
|
if err := db.WithContext(c.Request.Context()).Where("session_key = ?", token).First(&user).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
c.AbortWithStatusJSON(http.StatusUnauthorized, model.Error(http.StatusUnauthorized, "invalid token"))
|
|
return
|
|
}
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "load user failed"))
|
|
return
|
|
}
|
|
|
|
if sessionCache != nil {
|
|
_ = sessionCache.Set(c.Request.Context(), token, &user)
|
|
}
|
|
|
|
c.Set(ContextCurrentUserKey, &user)
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func extractToken(authHeader string) string {
|
|
// 常见格式:Authorization: Bearer <token>
|
|
if authHeader == "" {
|
|
return ""
|
|
}
|
|
parts := strings.SplitN(authHeader, " ", 2)
|
|
if len(parts) != 2 {
|
|
return ""
|
|
}
|
|
if !strings.EqualFold(parts[0], "Bearer") {
|
|
return ""
|
|
}
|
|
return strings.TrimSpace(parts[1])
|
|
}
|