feat(auth): 受信任内部调用方令牌直通(PINEAGENTS_INTERNAL_TOKEN)

- 命中内部令牌时鉴权层合成 root 身份,供 server-core 作为唯一入口无权限限制管理微服务
- 为空时关闭该能力;constant-time 比较防时序侧信道
This commit is contained in:
Pine
2026-08-29 00:31:34 +08:00
parent 07806a7d60
commit 502e8b5db5
2 changed files with 46 additions and 0 deletions
+11
View File
@@ -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
+35
View File
@@ -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)