Rest API с базой данных с несколькими арендаторами, разделенными клиентом

У меня есть база данных с несколькими арендаторами с составным ключом

clientId - docId

Маршрутизация выглядит так:

/api/controller/clientId/docId

Для аутентификации я использую "глобальное" имя пользователя, такое как адрес электронной почты + пароль, отправленный в HTTP-заголовке каждого запроса через https. Имя пользователя явно отображается клиенту и доступно на сервере.

Как правильно это сделать с отдыхом и иметь лучшую безопасность?

  • Маршрут, как указано выше, и просто убедитесь, что clientId в соответствии с именем пользователя совпадает с маршрутизацией

или

  • Измените маршрутизацию, как показано ниже, и получите clientId из базы данных, прежде чем сохранять запись?

    /api/controller/docId

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

Спасибо!

Ответ 1

Я думаю, что /api/controller/docId, вероятно, лучшая идея или использование единственного суррогатного ключа для представления ClientId и docId (мои предпочтения).

Если вам не нужно позволять клиентам просматривать другие ресурсы клиентов, я бы спрятал их из схемы URI, в худшем случае это может считаться утечкой информации, в лучшем случае это избыточно, поскольку вы аутентифицировали клиента и знаете, кто он такой. Это также накладные расходы, то есть вы все еще должны проверять идентификатор клиента в URL, который сопоставляется с именем пользователя и паролем запроса, поэтому вам нужно получить идентификатор клиента по каждому запросу в любом случае.

Если вы посмотрели, как работают другие многоузловые среды, например, Sales Force вы можете видеть, что они должны вывести клиента через механизм безопасности или достаточно удачливы иметь уникальный идентификатор для каждого объекта/ресурса.

Подход, который я видел, заключается в том, чтобы поместить идентификатор клиента (обычно это суррогатный ключ somekind, избегать разоблачения других пользователей db id!) в корне URL-адреса, например./API/{ClientID}/контроллер/DocId. В многоуровневой среде каждый ресурс, вероятно, по определению является уникальным для этого клиента.

Иногда для данного подхода возникает причина, заключающаяся в том, что наличие уникального URL-адреса для каждого клиента помогает с кешированием... /api/ {clientId}/controller/docId или/api/controller/{clientId}/docId

Краткий обзор базовой аутентификации

Ничего плохого в вашем подходе, но рассмотрите... вы можете получить идентификатор клиента, одновременно проверяя пароль и имя пользователя, и добавьте это как заявку на IPrinciple. По крайней мере, это тогда доступно в коде без каких-либо дальнейших поисков db, чтобы найти его (в течение срока действия этого запроса).

Далее сделаем шаг... рассмотрим двухэтапный механизм аутентификации, в котором выдается токен (после правильного имени пользователя и пароля) с идентификатором клиента фактически в токене в качестве претензии. Таким образом, последующие запросы с токеном означают, что вам не нужно будет возвращать db для каждого запроса для аутентификации и получения информации. Взгляните на токены на предъявителя OAuth http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html (обязательно подпишите их) или некоторые другие подходы...

Ответ 2

Подход Mark полностью действителен, однако я использую /tenant/docid, потому что у каждого арендатора есть другая база данных. Если вы не включаете арендатора в URI, тогда было бы настоящей болью, пытаясь решить, к какой базе данных подключиться и искать этот документ.