fix: allow agent JWT to use attached online_db_id (Z14c)

Agent tokens use agent_id as user_id while Binding is under the human member; authorize schema/push/ensure against the agent's mounted OnlineDBID.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
whm
2026-08-05 18:22:57 +08:00
parent 4fae7ae718
commit bb59bb5efd
3 changed files with 63 additions and 10 deletions

View File

@@ -198,8 +198,8 @@ func authorizeUserSyncPush(svcCtx *svc.ServiceContext, w http.ResponseWriter, r
return authorizeUserOnlineDB(svcCtx, w, r, channelID, item.OnlineDBID, "用户自助 push 须带 online_db_id且须为本人 Binding")
}
// authorizeUserOnlineDB带 online_db_id 时一律按本人 Binding 校验(含有「数据同步」的人类管理员)。
// 仅「数据同步」且未带 online_db_id 时保持租户级管理路径(智能体/管理员兼容)
// authorizeUserOnlineDB带 online_db_id 时本人 Binding或智能体挂载落点匹配Z14c)。
// 仅「数据同步」且未带 online_db_id 时保持租户级管理路径。
func authorizeUserOnlineDB(svcCtx *svc.ServiceContext, w http.ResponseWriter, r *http.Request, channelID, onlineDBID, emptyMsg string) bool {
online := strings.TrimSpace(onlineDBID)
wide := authx.SyncTenantWide(r.Context())
@@ -215,8 +215,41 @@ func authorizeUserOnlineDB(svcCtx *svc.ServiceContext, w http.ResponseWriter, r
}
uid := authx.UserID(r.Context())
tid := syncTenantID(r)
if !svcCtx.DBSync.Store().UserOwnsOnlineDB(tid, uid, channelID, online) {
authx.WriteError(w, http.StatusForbidden, "无权访问该 online_db_id非本人 Binding / 非公司共享库)")
if svcCtx.DBSync.Store().UserOwnsOnlineDB(tid, uid, channelID, online) {
return true
}
// Z14c智能体 JWT 的 user_id=agent_idBinding 记在人类成员上;放行 agents/me / ticket 挂载的 online_db_id
if agentOwnsOnlineDB(svcCtx, r, tid, channelID, online) {
return true
}
authx.WriteError(w, http.StatusForbidden, "无权访问该 online_db_id非本人 Binding / 非智能体挂载落点 / 非公司共享库)")
return false
}
// agentOwnsOnlineDB 当前智能体账号是否已挂载该 online_db_id及可选 channel
func agentOwnsOnlineDB(svcCtx *svc.ServiceContext, r *http.Request, tenantID int64, channelID, onlineDBID string) bool {
if svcCtx == nil || svcCtx.Agents == nil {
return false
}
aid := authx.AgentID(r.Context())
if aid <= 0 {
// 兼容旧票Role=智能体 时 UserID 即 AgentID
if authx.Role(r.Context()) == authx.Role智能体 {
aid = authx.UserID(r.Context())
}
}
if aid <= 0 || tenantID <= 0 {
return false
}
acc, err := svcCtx.Agents.Get(r.Context(), tenantID, aid)
if err != nil || acc == nil {
return false
}
if strings.TrimSpace(acc.OnlineDBID) != strings.TrimSpace(onlineDBID) {
return false
}
ch := strings.TrimSpace(channelID)
if ch != "" && strings.TrimSpace(acc.ChannelID) != "" && strings.TrimSpace(acc.ChannelID) != ch {
return false
}
return true