diff --git a/common/env.go b/common/env.go index 1aa340f..c774048 100644 --- a/common/env.go +++ b/common/env.go @@ -6,6 +6,17 @@ import ( "strconv" ) +// InternalAccessToken 受信任内部调用方令牌:命中后鉴权层直接合成 root 身份, +// 放开全部管理/root 端点(用于 server-core 作为唯一入口无权限限制地管理微服务)。 +// 为空时关闭该能力。 +// +// 需在请求时惰性读取(而非包 init 时),因为 main() 里 godotenv.Load(".env") +// 晚于包 init 执行,过早读取会拿到空串。 +func InternalAccessToken() string { + return os.Getenv("PINEAGENTS_INTERNAL_TOKEN") +} + + func GetEnvOrDefault(env string, defaultValue int) int { if env == "" || os.Getenv(env) == "" { return defaultValue diff --git a/middleware/auth.go b/middleware/auth.go index 9f2a9df..f82f52a 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -7,6 +7,8 @@ import ( "net/http" "strings" + "crypto/subtle" + "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/constant" "github.com/QuantumNous/new-api/i18n" @@ -42,7 +44,40 @@ func validUserInfo(username string, role int) bool { return true } +// bypassTrustedInternal 受信任内部调用方(server-core):命中 PINEAGENTS_INTERNAL_TOKEN 时 +// 不查库、直接合成 root 身份,放开 AdminAuth/RootAuth/RequirePermission 的权限限制。 +// 返回 true 表示已处理(含 c.Next())。 +func bypassTrustedInternal(c *gin.Context, minRole int) bool { + internalToken := common.InternalAccessToken() + if internalToken == "" { + return false + } + raw, ok := authorizationToken(c.GetHeader("Authorization")) + if !ok || subtle.ConstantTimeCompare([]byte(raw), []byte(internalToken)) != 1 { + return false + } + user := &model.UserBase{ + Id: -1, + Group: "default", + Role: common.RoleRootUser, + Status: common.UserStatusEnabled, + Username: "internal-server", + } + identity := service.AuthIdentity{UserID: user.Id, UserAuthVersion: 1} + setDashboardAuthContext(c, user, identity, true) + var auditWriter *auditResponseWriter + if minRole >= common.RoleAdminUser { + auditWriter = beginAdminAudit(c) + } + c.Next() + finishAdminAudit(c, auditWriter) + return true +} + func authHelper(c *gin.Context, minRole int) { + if bypassTrustedInternal(c, minRole) { + return + } user, identity, useAccessToken, err := authenticateDashboardRequest(c) if err != nil { writeDashboardAuthError(c, err)