strapi - разрешить пользователю получать только данные, связанные с ним

Обычно вошедший в систему пользователь получает все записи типа контента.

Я создал тип контента "сниппеты" (_id,name,content,users<<->>snippets)

<<->> означает отношение "имеет и принадлежит многим".

Я создал несколько тестовых пользователей и сделал запрос: curl -H 'Authorization: Bearer eyJ...' http://localhost:1337/snippets/

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

Как можно изменить запрос fetchAll(ctx.query);, чтобы учесть это, чтобы он выполнял что-то вроде fetchAll(ctx.state.user.id); в /-route -> _ 7_-метод?

Основной метод поиска здесь:

find: async (ctx) => {

    if (ctx.query._q) {
      return strapi.services.snippet.search(ctx.query);
    } else {
      return strapi.services.snippet.fetchAll(ctx.query);
    }
},

Подвопрос: знает ли strapi, какой пользователь вошел в систему, когда я выполняю аутентификацию с использованием токена-носителя?


person sgohl    schedule 12.11.2018    source источник


Ответы (3)


Вы можете настроить маршрут / snippets / me в конфигурации сниппетов.

Этот маршрут может вызвать метод контроллера Snippets.me, который будет проверять пользователя, а затем запрашивать фрагменты на основе пользователя.

Итак, в api/snippet/config/routes.json будет что-то вроде:

    {
      "method": "GET",
      "path": "/snippets/me",
      "handler": "Snippets.me",
      "config": {
        "policies": []
      }
    },

Затем в контроллере (api/snippet/controllers/Snippet.js) вы можете сделать что-то вроде:

  me: async (ctx) => {
    const user = ctx.state.user;    
    if (!user) {
      return ctx.badRequest(null, [{ messages: [{ id: 'No authorization header was found' }] }]);
    }

    const data = await strapi.services.snippet.fetch({user:user.id});  

    if(!data){
      return ctx.notFound();
    }

    ctx.send(data);
  },

Затем вы должны предоставить аутентифицированным пользователям разрешения для маршрута me, а не для всего маршрута сниппетов.

person Moses    schedule 12.11.2018
comment
Я вижу, что это ваш первый / единственный ответ, и я хотел выразить вам искреннюю благодарность за то, что вы так любезно зарегистрировались и помогли мне! :-) - person sgohl; 13.11.2018
comment
Я получаю только один фрагмент. делает выборку ({user: user.id}); получить только одну запись? fetchAll ({user: user.id}) не дает никаких результатов - person sgohl; 13.11.2018
comment
возможны ли запросы? _sort / find с этим решением? - person sgohl; 13.11.2018
comment
Можно ли расширить запрос ctx.query, чтобы ограничить его частью user: user.id? чтобы я мог использовать модель поиска / -route - person sgohl; 13.11.2018
comment
Создание запроса может быть отключено с помощью fetchAll (). Если на пользователя приходится более одного сниппета, это должно сработать. Поиграйте с этим. _sort и другие параметры должны работать, вам просто нужно создать запрос, включая эти свойства. - person Moses; 13.11.2018
comment
Я не совсем уверен, что вы задаете в последнем вопросе, но я предложил этот метод потому, что объект пользователя существует на бэкэнде. AFAIK, вы не знаете идентификатор пользователя, пока не получите серверную часть. Чтобы использовать метод / route (который, я думаю, вы предлагаете, возможно, / route /: id?), Вы должны уже знать, какой пользователь прошел аутентификацию, что означает, что данные поступали из внешнего интерфейса, что означает, что ваш пользовательский объект во внешнем интерфейсе, что является плохой идеей, он содержит всю информацию о вашем пароле. - person Moses; 13.11.2018
comment
пользователь хранится только в серверной части strapi. Фронтенд еще не существует. Прежде чем я смогу выполнить запрос (я имитирую это с помощью curl или бессонницы), я должен пройти аутентификацию, поэтому я получаю токен на предъявителя, и с этим токеном на предъявителя я могу сделать запрос. В этот момент strapi должен знать, кто я, потому что я отправил свой токен вместе со своим запросом. И я действительно имею в виду основной маршрут, в моем случае path: / snippets - который использует find module.export. поэтому вместо этого верните strapi.services.snippet.fetchAll (ctx.query); Мне нужно что-то, что расширяет ctx.query с моим {user: user.id}, я думаю - person sgohl; 13.11.2018
comment
К сожалению, он возвращает элемент, не принадлежащий зарегистрированному пользователю. Знает ли strapi, какой пользователь вошел в систему, когда я выполняю аутентификацию по токену на предъявителя? Или эта аутентификация токена на самом деле просто легитимация? тогда это не должно называться аутентификацией - person sgohl; 13.11.2018
comment
ctx.state.user должен быть объектом авторизованного пользователя. Если фрагменты имеют отношение к пользователям, вы сможете найти связанные фрагменты по идентификатору пользователя. Не видя вашего кода и вашего проекта, я не могу говорить больше о деталях. - person Moses; 14.11.2018
comment
Могу только посоветовать вам поискать фильтры в документации strapi. если типы содержимого фрагментов содержат пользователь в качестве свойства, вы должны иметь возможность создать объект запроса, используя этого пользователя в качестве фильтра, и отправить его с помощью fetchAll. - person Moses; 14.11.2018
comment
Это сработает, спасибо !. Однако как насчет плагина GraphQL? Это не повлияет, поскольку контроллер зависит от веб-API, не так ли? Должно быть более ориентированное на данные решение, а не реализация для конкретной точки доступа api. Просто думаю вслух ... - person Sergey Lukin; 10.10.2019
comment
.fetch теперь нужно заменить на .find - person Made in Moon; 20.06.2020

Вышесказанное верно, за исключением более новых версий ремешка. Используйте find, а не fetch :)

const data = await strapi.services.snippet.find({ user: user.id });

Strapi v3.0.0-beta.20

person Jeremy Rajan    schedule 16.04.2020
comment
Откуда взялся сервис сниппетов? Я получаю TypeError: не удается прочитать свойство "найти" неопределенного - person Aido; 16.04.2020
comment
Он будет доступен в файле контроллера, если вы будете следовать правильной структуре контроллера. Или используйте интерфейс командной строки strapi для создания контроллера. - person Jeremy Rajan; 18.04.2020
comment
Ох, это отдельный объект. Есть ли способ сделать это для пользовательских объектов? / users / me предназначен только для запросов на получение. - person Aido; 18.04.2020

Можно было бы расширить запрос, используемый find и findOne в контроллерах, с ограничением в отношении вошедшего в систему пользователя. В этом случае вы также можете захотеть адаптировать count конечную точку, чтобы она была согласованной.

Это приведет к:

withOwnerQuery: (ctx, ownerPath) => {
  const user = ctx.state.user;
  if (!user) {
    ctx.badRequest(null, [
      { messages: [{ id: "No authorization header was found" }] },
    ]);
    return null;
  }
  return { ...ctx.query, [ownerPath]: user.id };
};

find: async (ctx) => {
    ctx.query = withOwnerQuery(ctx, "owner.id");
    if (ctx.query._q) {
      return strapi.services.snippet.search(ctx.query);
    } else {
      return strapi.services.snippet.fetchAll(ctx.query);
    }
},

// analogous for for findOne

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

Такое решение будет работать с плагином GraphQL.

person manuelkruisz    schedule 11.05.2020