You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Realm+MongoDB Atlas Flex Sync写入权限错误求助

问题原因与解决办法

核心问题:数据库规则配置逻辑错误

你的Realm写入权限错误,根源是MongoDB Atlas的规则配置混淆了用户身份校验和文档范围过滤的逻辑:

  • apply_when字段是用来判断当前用户是否具备该角色的资格,而非限制文档的归属
  • document_filters字段才是用来限定用户能读写的文档范围

你当前的规则中,apply_when里的"accountId": "%%user.id"是在检查用户对象(而非文档)中是否存在accountId字段且等于用户ID,这不符合匿名登录用户的身份结构,导致角色无法正确匹配;同时document_filters设为true意味着允许读写所有文档,这和你实际要实现的"用户只能读写自己的Venue"逻辑冲突,最终触发权限拦截。

解决步骤

1. 修正数据库规则配置

将Atlas的规则替换为以下内容,确保逻辑正确:

{
  "roles": [
    {
      "name": "readAndWriteOwnVenues",
      "apply_when": {
        "%%user.id": {"$exists": true}
      },
      "document_filters": {
        "write": {"accountId": "%%user.id"},
        "read": {"accountId": "%%user.id"}
      },
      "read": true,
      "write": true,
      "insert": true,
      "delete": true,
      "search": true
    }
  ]
}
  • apply_when: 仅当用户已登录(存在用户ID)时,才赋予该角色
  • document_filters: 限制用户只能读写accountId字段等于自身用户ID的文档,和你的Venue模型字段对应

2. 调整Flexible Sync订阅查询

当前的全量订阅QuerySubscription<Venue>会同步所有Venue文档,这既不符合权限规则,也浪费资源。修改订阅逻辑,只同步当前用户的Venue:

@MainActor
func initialize() async throws {
    user = try await app.login(credentials: Credentials.anonymous)
    // 先获取用户的accountId,用于订阅过滤
    guard let account = try await getUserAccountById() else {
        throw NSError(domain: "RealmManager", code: -2, userInfo: [NSLocalizedDescriptionKey: "User account not found"])
    }

    let configuration = user?.flexibleSyncConfiguration(initialSubscriptions: { subs in
        if subs.first(named: "userAccounts") == nil {
            subs.append(QuerySubscription<UserAccount>(name: "userAccounts"))
        }
        if subs.first(named: "venues") == nil {
            // 订阅当前用户的Venue文档
            let venueQuery = NSPredicate(format: "accountId == %@", account._id)
            subs.append(QuerySubscription<Venue>(name: "venues", query: venueQuery))
        }
    }, rerunOnOpen: true)

    realm = try await Realm(configuration: configuration!, downloadBeforeOpen: .always)
}

3. 验证写入逻辑

确认createVenue方法中,venue.accountId确实被设置为当前用户的account._id,且写入操作在正确的Realm实例中执行。你的现有代码这部分逻辑是正确的,但可以添加日志验证account._id和venue.accountId的一致性。

额外说明

  • 移除规则后能写入是因为此时没有权限校验,所有操作都被允许,但这在生产环境中存在严重安全风险
  • 错误码231是Realm Flexible Sync的权限拦截错误,通常由规则不匹配或订阅范围与规则冲突导致

内容的提问来源于stack exchange,提问作者Etienne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 06:31:16