Пользовательская роль FaunaDB для ограничения доступа только к собственным данным

Я создаю образец приложения для оценки FaunaDB и Nextjs

Мой план состоит в том, чтобы веб-приложение аутентифицировалось отдельно, затем создавало пользователя на FaunaDB. Затем создавало токен на FaunaDB и позволяло пользователю подключаться через его собственный секретный токен.

Я считаю, что я на правильном пути, чтобы заставить эту модель работать, но я столкнулся с проблемой с пользовательской ролью в FaunaDB.

Модель данных - Пользователь - ›Доска -› Задачи, и в этом вопросе я воспользуюсь доступом к доскам.

Вот код для настраиваемой роли

{
  ref: Role("Free_Tier_Role"),
  ts: 1601934616790000,
  name: "Free_Tier_Role",
  membership: [
    {
      resource: Collection("user"),
      predicate: Query(
        Lambda("ref", Select(["data", "isEnabled"], Get(Var("ref"))))
      )
    }
  ],
  privileges: [
    {
      resource: Collection("user"),
      actions: {
        read: true,
        write: false,
        create: false,
        delete: false,
        history_read: false,
        history_write: false,
        unrestricted_read: false
      }
    },
    {
      resource: Collection("board"),
      actions: {
        read: Query(
          Lambda(
            "ref",
            Equals(Identity(), Select(["data", "owner"], Get(Var("ref"))))
          )
        ),
        write: Query(
          Lambda(
            ["oldData", "newData"],
            And(
              Equals(
                Select("id", Identity()),
                Select(["data", "owner"], Var("oldData"))
              ),
              Equals(
                Select(["data", "owner"], Var("oldData")),
                Select(["data", "owner"], Var("newData"))
              )
            )
          )
        ),
        create: Query(
          Lambda(
            "newData",
            And(
              Equals(Identity(), Select(["data", "owner"], Var("newData"))),
              LT(Count(Match(Index("board_by_owner"), Identity())), 3)
            )
          )
        ),
        delete: Query(
          Lambda(
            "ref",
            Equals(Identity(), Select(["data", "owner"], Get(Var("ref"))))
          )
        ),
        history_read: false,
        history_write: false,
        unrestricted_read: false
      }
    },
    {
      resource: Collection("task"),
      actions: {
        read: Query(
          Lambda(
            "ref",
            Equals(Identity(), Select(["data", "owner"], Get(Var("ref"))))
          )
        ),
        write: Query(
          Lambda(
            ["oldData", "newData"],
            And(
              Equals(
                Select("id", Identity()),
                Select(["data", "owner"], Var("oldData"))
              ),
              Equals(
                Select(["data", "owner"], Var("oldData")),
                Select(["data", "owner"], Var("newData"))
              )
            )
          )
        ),
        create: Query(
          Lambda(
            "newData",
            And(
              Equals(Identity(), Select(["data", "owner"], Var("newData"))),
              LT(Count(Match(Index("task_by_owner"), Identity())), 10)
            )
          )
        ),
        delete: Query(
          Lambda(
            "ref",
            Equals(Identity(), Select(["data", "owner"], Get(Var("ref"))))
          )
        ),
        history_read: false,
        history_write: false,
        unrestricted_read: false
      }
    },
    {
      resource: Index("task_by_owner"),
      actions: {
        unrestricted_read: false,
        read: false
      }
    },
    {
      resource: Index("board_by_owner"),
      actions: {
        unrestricted_read: false,
        read: false
      }
    }
  ]
}

Проблема, с которой я столкнулся: когда я вхожу в систему с помощью токена пользователя, и этот пользователь является владельцем доски, я получаю пустой список

> Map(Paginate(Documents(Collection('board'))),Lambda('x', Get(Var('x'))))
{ data: [] }

Чтобы проверить, что они имеют одинаковое значение, я запускаю эту команду в оболочке на панели инструментов.

Select(["data", "owner"], Get(Ref(Collection("board"), "278575744915866117")))

Ref(Collection("user"), "278571699875611143")

>> Time elapsed: 28ms

И запустите Identity () на моем экземпляре с аутентификацией по токену

> Identity()
Ref(Collection("user"), "278571699875611143")
>                                 

P.S. до этого подхода я сравнивал номер идентификатора только с помощью Select (['data', 'ownerId'], Ref), но это не сработало, даже когда я пытался преобразовать как ToString, так и ToNumber


person Nabil Alhusail    schedule 05.10.2020    source источник
comment
Вы пробовали создать индекс, который фильтрует по владельцу вместо использования Documents()?   -  person Pier    schedule 06.10.2020
comment
@Pier Это сработает, но это будет опасно. В основном, если вы когда-нибудь забудете фильтрацию по владельцу, тогда этот запрос покажет документы всех. Фильтрация в разрешении позволит вам запрашивать все документы, в то время как FaunaDB вернет только документы текущего пользователя.   -  person Nabil Alhusail    schedule 09.10.2020
comment
Да, очевидно, что вам понадобится Lambda () в разрешении роли, чтобы проверить наличие ссылки на владельца.   -  person Pier    schedule 10.10.2020


Ответы (1)


Вау, мне потребовалось около 2 дней, чтобы диагностировать, что происходит

По сути, код, который я написал выше, работает только для того, чтобы позволить владельцу доски или задачи видеть свои собственные элементы и обновлять их.

Но проблема для меня была с членством, оно работало не так, как ожидалось.

Вот шаги решения, которые вам нужно выполнить, если вы обнаружите, что у вас неработающие разрешения.

Убедитесь, что роль относится к вашему пользователю Вот как я это сделал

  1. Создайте пример функции test_newFunc, используя код по умолчанию Query(Lambda("x", Add(Var("x"), Var("x"))))
  2. Создайте новую роль и включите всех «пользователей» и разрешите вызывать test_newFunc.
  3. Создайте токен и запустите оболочку, используя секрет токена
  4. Запустить Call("test_newFunc", 2)
  5. Для меня я добавил предикат членства как

Lambda("docRef", Equals(true, Select(["data", "isEnabled"], Get(Var("docRef")))))

Это означает, что у пользователя должно быть поле данных isEnabled, и его значение должно быть истинным.

Затем проверьте, переключая значение этого поля для олицетворенного пользователя, пока не подтвердите, что эта роль применяется.

Как только этот шаг будет очищен, вы можете протестировать предикаты для каждого разрешения.

Надеюсь, это будет полезно для будущих разработчиков, которые столкнутся с этой проблемой.

person Nabil Alhusail    schedule 06.10.2020