|
|
// Copyright (C) 2024 veypi <i@veypi.com>
|
|
|
// 2025-03-04 16:08:06
|
|
|
// Distributed under terms of the MIT license.
|
|
|
|
|
|
package auth
|
|
|
|
|
|
import (
|
|
|
"strings"
|
|
|
|
|
|
"github.com/veypi/vbase/cfg"
|
|
|
"github.com/veypi/vbase/libs/cache"
|
|
|
"github.com/veypi/vbase/libs/jwt"
|
|
|
"github.com/veypi/vbase/models"
|
|
|
"github.com/veypi/vigo"
|
|
|
)
|
|
|
|
|
|
// AuthMiddleware 统一认证中间件
|
|
|
// 1. JWT认证: 解析token,验证有效性,设置用户信息
|
|
|
// 2. 组织上下文: 如果请求包含org_id,验证用户成员身份,设置组织信息
|
|
|
func AuthMiddleware() func(*vigo.X) error {
|
|
|
return func(x *vigo.X) error {
|
|
|
// === 1. JWT 认证部分 ===
|
|
|
tokenString := extractToken(x)
|
|
|
if tokenString == "" {
|
|
|
return vigo.ErrUnauthorized.WithString("missing token")
|
|
|
}
|
|
|
|
|
|
// 解析token
|
|
|
claims, err := jwt.ParseToken(tokenString)
|
|
|
if err != nil {
|
|
|
if err == jwt.ErrExpiredToken {
|
|
|
return vigo.ErrTokenExpired
|
|
|
}
|
|
|
return vigo.ErrTokenInvalid
|
|
|
}
|
|
|
|
|
|
// 检查token是否在黑名单中
|
|
|
if cache.IsEnabled() {
|
|
|
blacklisted, _ := cache.IsTokenBlacklisted(claims.ID)
|
|
|
if blacklisted {
|
|
|
return vigo.ErrUnauthorized.WithString("token has been revoked")
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 将用户信息存入上下文
|
|
|
x.Set("user_id", claims.UserID)
|
|
|
x.Set("user_name", claims.Username)
|
|
|
x.Set("user_orgs", claims.Orgs)
|
|
|
x.Set("token_claims", claims)
|
|
|
|
|
|
// === 2. 组织上下文部分 ===
|
|
|
orgID := x.Request.Header.Get("X-Org-ID")
|
|
|
if orgID == "" {
|
|
|
orgID = x.Request.URL.Query().Get("org_id")
|
|
|
}
|
|
|
|
|
|
if orgID == "" {
|
|
|
// 没有指定组织,仅完成用户认证
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// 验证用户是否为组织成员
|
|
|
var member models.OrgMember
|
|
|
if err := cfg.DB().Where("org_id = ? AND user_id = ? AND status = ?",
|
|
|
orgID, claims.UserID, models.MemberStatusActive).First(&member).Error; err != nil {
|
|
|
return vigo.ErrForbidden.WithString("you are not a member of this organization")
|
|
|
}
|
|
|
|
|
|
x.Set("org_id", orgID)
|
|
|
x.Set("org_roles", member.RoleIDs)
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func extractToken(x *vigo.X) string {
|
|
|
auth := x.Request.Header.Get("Authorization")
|
|
|
if auth != "" {
|
|
|
if len(auth) > 7 && strings.HasPrefix(auth, "Bearer ") {
|
|
|
return auth[7:]
|
|
|
}
|
|
|
}
|
|
|
return x.Request.URL.Query().Get("access_token")
|
|
|
}
|