Здравствуйте, Sinclair, Вы писали:
КЛ>>система типов это только про поля, а что со строками? КЛ>>это не гибко S>Излишняя гибкость, в целом, только вредит. Но фильтрация, в отличие от проекции, не нарушает никаких инвариантов.
не понял
S>Поэтому в ней запросто можно учитывать предикаты, в том числе и построенные на токене пользователя. S>По-прежнему у нас границы безопасности совпадают с границами ресурса. S>Смотрите: вот я делаю какой-нибудь S>
S>GET /invoices/
S>
S>И мне приезжает какой-то список инвойсов. Как правило — без деталей, только ссылки. S>И если я пойду по этим ссылкам, типа GET /invoices/32423423423/, то скорее всего буду получать 200 Ok. S>А вот те из инвойсов, на которые у меня прав нет, дадут при прямом обращении 403 либо 404, и в общем списке фигурировать не будут.
ну у нас так же, в чем поинт?
S>Для проектирования безопасности у нас недостаточно вводных.
смешно
КЛ>>а что он делает? S>Он делает возможность формировать запросы к иерархии объектов, без всех плюшек REST.
да не, по сути он дает тебе query language к базе
КЛ>>а как вы тестируете все остальное, что отдает данные на основании пользовательского контекста?
S>
отвечай!
КЛ>>да, но выставляет наружу псевдо-бд S>Есть много разных способов выставить наружу псевдо-бд, и не все из них одинаково полезны. S>Надо понимать, какая проблема решается.
Здравствуйте, Константин Л., Вы писали:
КЛ>то есть пермисии определяются декларативно просто наличием полей в типе? ну-ну
Не уверен, что я понял ваш вопрос, но скорее всего ответ "нет". КЛ>"хорошо это когда хорошо".
А то. КЛ>тогда _какую_ проблему решают твои виртуальные ресурсы? никакую
Конечно. Они не создают проблему. А решают они задачу — задачу ограничения доступа к определённым атрибутам для определённых групп пользователей.
КЛ>серьезные приложения это софт для АЭС, там можно. В 99 процентах других случаев твоя модель не работает, такая моя оценка
Софт для АЭС тут ни при чём. А серьёзные приложения — это те, к примеру, которые автоматизируют деятельность, подлежащую регулированию каким-нибудь FinCEN.
Когда у вас есть реальная перспектива продолбать крипты суммарной стоимостью под миллиард, рассуждения в стиле "у меня в коде всё было правильно, это тупой админ нечаянно выдал лишнюю пермиссию на один из атрибутов одного из объектов одному из пользователей" не сильно помогают избежать кусания локтей.
КЛ>при чем здесь вообще апи, когда мы говорим про то, как делать секьюрити внутри?
С чего это вдруг?
Мы всю дорогу говорили именно про то, как должен выглядеть API снаружи. То, что там внутри, в первую очередь определяется контрактом протокола, затем — общей архитектурой решения. А уже дальше идут подробности реализации. Собственно, спор-то и идёт о том, то ли выставлять наружу 1 ресурс, схема которого сложным образом зависит от погоды на Венере, то ли выставлять наружу N ресурсов с предсказуемыми схемами.
КЛ>Google Cloud так и делает если что
Не знаком с Google Cloud, поэтому не могу осмысленно обсуждать его поведение. Если приведёте пример API-запроса, и пример клиента этого API, который этот запрос отправляет и его результатами пользуется, можно будет что-нибудь конструктивно обсудить.
КЛ>домыслы
А то. Основанные на многолетнем опыте проектирования, изготовления, и использования различных сервисов
КЛ>дорогостоящий саппорт? дороже разработки?
Естественно. Потому что разработка делается 1 раз, а саппорт — всю жизнь. Вы себе представляете себестоимость 1 инцидента в саппорте?
КЛ>ваши роли в субд и есть часть пермиссий через субд
Какая-то путаница. У меня нет никаких "ролей в СУБД".
КЛ>а что тогда надо использовать в твоем случае?
Запросы.
Пишем
IQueryable<OutboundInvoice> InvoicesSentBy(CompanyID currentCompany) =>
from i in db.OutboundInvoices where i.originator = currentCompany select i;
IQueryable<InboundInvoice> InvoicesSentTo(CompanyID currentCompany) =>
from i in db.InboundInvoices where i.destination = currentCompany select i;
Всё. Поверх этого в контроллере проверяем, что у текущего пользователя есть пермиссия на доступ к InboundInvoices/OutboundInvoices. Всё.
КЛ>даже не буду комментировать, причем тут несколько сервисов и их взаимодействие я не понимаю, это вне контекста нашего обсуждения
Это очень странно. Топик называется "помогите спроектировать микросервисное приложение". Как мы ухитрились выкинуть из контекста API для взаимодействия между микросервисами?
И что тогда вообще осталось в контексте?
КЛ>кто так вообще делает? выглядит как полная дичь если честно
Я не знаю. Но если вы вдруг захотите применить Row Level Security из любой СУБД, в которой она есть, вам так и придётся делать.
КЛ>>>select * from rows r КЛ>>>join rows_perms p on r.id = p.r_id КЛ>>> where p.perm = 'row_read' and p.user_id = :userid S>>Прекрасно. Вы себе представляете производительность такого решения? Когда у нас табличка на пару миллионов строк, и есть тысяча пользователей с частично пересекающимися правами на эти строки?
КЛ>да, индекс на rows_perms.user_id и будет быстро, Ну ок.
КЛ>плюс там еще в 99 процентах будет предикат на индексированное поле как часть фильтра поискового запроса.
И это всё ещё будет медленнее, чем прямой поиск по предикату, который применяется к единственной таблице (см. пример кода с Invoices выше). КЛ>да, часто данные для всех лежать в одной таблице и когда нужен row-level security у тебя просто нет выбора. либо копии данных (твои views видимо) либо так.
Эмм, views никаких "копий данных" не создают. Если хотите — могу рассказать, как они работают.
Да, если вам некомпететный продакт навязал вот эту вот модельку "кому угодно можно выдавать доступ на что угодно", то выбора действительно нет. Ну, точнее, даже там бывают возможности поиграть с оптимизацией, но не очень большие. Тут вопросов нет. Вопрос как раз в том, как проектировать API, чтобы вот таких вот необходимостей не возникало. КЛ>но это на запрос коллекции, а на запрос одного ресурса вообще все быстро потому что индекс и на rows_perms.id
КЛ>первый пример довольно универсален, он иллюстрирует подход "на основании токена фильтруем резалтсет и тп"
Нет конечно. В первом примере нет решительно никакой возможности управлять видимостью отдельных атрибутов на уровне отдельных объектов. КЛ>а в твоем случае как? у тебя же схема прибита гвоздями
Во-первых, в моём случае этого не надо, т.к. я против самой идеи разделять доступ "по-объектно". Это ухудшает сразу примерно всё: и эффективность, и безопасность, и удобство использования.
Во-вторых, если даже нам такое припёрло, у меня состав заказанных полей известен в момент получения запроса, и мне не надо пытаться "доставать всё, для чего довольно пермиссий", с риском достать что-то не нужное или неожиданное.
КЛ>как тут помогают роутеры?
Кто такие роутеры и почему они должны мне помогать?
КЛ>да ну я тебе сделаю отдельный endpoint, но внутри будет один движок по доставке данных, который может тебе отдавать 403 в когда надо
Ну так и слава байту. С чем спорим-то тогда?
КЛ>мы потешаемся не над ним, а над тем, что ты полагаешься только на него
Непонятно, что значит "только".
КЛ>на комбинаторный взрыв сущностей
Комбинаторный взрыв сущностей у нас случился в тот момент, когда кто-то решил разрешать доступ к различным атрибутам ресурса при помощи независимых пермиссий. Дальше вопрос только в том, признаём мы его или нет, и что мы с ним делаем.
Когда у нас состав атрибутов явно заказывается в урле, нам очень легко такое тестировать:
1. делаем запрос к ?$include(attribute1) с токеном без пермиссии на attribute1, убеждаемся, что получаем 403
2. делаем запрос к ?$include(attribute1) с токеном с пермиссией на attribute1, убеждаемся, что получаем 200.
3. делаем запрос к ?$include(attribute1) с токеном с полными пермиссиями, убеждаемся, что получаем 200 и в ответе нет никаких лишних атрибутов.
4. Повторяем так для всех атрибутов, доступ к которым контролируется пермиссиями.
третье — факультативно: это если мы не верим в то, что код контроллера факторизован на предмет запрошенных атрибутов. Факторизацию можно отдельно проверять юнит-тестами.
Это гораздо надёжнее, чем пытаться перебирать все комбинации пермиссий и смотреть, какой получится результат.
КЛ>сколько раз мы уже это слышали по поводу всего. похоже на отмазку для неадекватного задаче решения
Как скажете.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Если мне вдруг приезжает массив, где у каких-то объектов нет senderName, то это нарушает приведённую здесь спецификацию типа.
Можно, конечно, принудительно приписать вопросики ко всем свойствам этого интерфейса, и написать обработку в приложении на каждый такой случай, но это, скажем так, непрактично.
А вот если мне приезжает массив, в котором не 100, а 10, или 0 элементов, инвариант сохранён. Я в любом случае не ожидаю, что мне вернётся ровно 100 элементов.
КЛ>ну у нас так же, в чем поинт?
Не знаю, как "у вас", а у исходного оппонента, судя по всему, в JSON будет список не ссылок, а объектов, причём состав объектов произвольно зависит не от самих объектов или аргументов запроса, а от наличия в токене тех или иных пермиссий.
КЛ>смешно
А вы всегда проектируете безопасность на основании описаний вроде "у нас есть пять типов отчётов, один из них внутренний, другой внешний". Вам сразу всё понятно, и можно бежать нарезать таблички в базе?
Я раньше и сам выяснял подробности проекта на основании телепатии и ясновидения, но лет 15 тому мне их за неуплату отключили, поэтому я предпочитаю проектировать на основании установленных фактов, а также вероятных будущих изменений.
КЛ>да не, по сути он дает тебе query language к базе
По сути там вообще может не быть никакой базы.
КЛ>отвечай!
Зависимость от контекста называется "модальностью" и является одним из признаков плохого проектирования. Такой зависимости нужно по возможности избегать.
Если уж никак-никак от неё избавиться не удалось, нужно факторизовывать пространство состояний для этого контекста. И следить за тем, чтобы факторизация была корректной, т.е. изоляция между ортогональными классами состояний должна сохраняться.
Успешная факторизация позволяет нам перейти от K*M тестов к K+M тестам. Всё.
КЛ>ну начинается! отлыниваешь )
Если вы хотите конструктивного обсуждения, можно попытаться взять какую-нибудь практическую задачу и посмотреть, как её решать в стиле REST — как с помощью микросервисов, так и без оных.
Можно попытаться понять, ради чего вообще может в голову прийти "выставлять наружу псевдо-бд", и как это делать правильно, и чем это отличается от неправильного решения.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Константин Л., Вы писали:
КЛ>>то есть пермисии определяются декларативно просто наличием полей в типе? ну-ну S>Не уверен, что я понял ваш вопрос, но скорее всего ответ "нет". КЛ>>"хорошо это когда хорошо". S>А то. КЛ>>тогда _какую_ проблему решают твои виртуальные ресурсы? никакую S>Конечно. Они не создают проблему. А решают они задачу — задачу ограничения доступа к определённым атрибутам для определённых групп пользователей.
а теперь читаем выше твой же ответ — "то есть пермисии определяются декларативно просто наличием полей в типе? ну-ну" — "...но скорее всего ответ "нет".
задача ограничения доступа это и есть по сути то, что решают пермиссии. то есть ответ да, просто ты не понимаешь уже что пишешь
КЛ>>серьезные приложения это софт для АЭС, там можно. В 99 процентах других случаев твоя модель не работает, такая моя оценка S>Софт для АЭС тут ни при чём. А серьёзные приложения — это те, к примеру, которые автоматизируют деятельность, подлежащую регулированию каким-нибудь FinCEN. S>Когда у вас есть реальная перспектива продолбать крипты суммарной стоимостью под миллиард, рассуждения в стиле "у меня в коде всё было правильно, это тупой админ нечаянно выдал лишнюю пермиссию на один из атрибутов одного из объектов одному из пользователей" не сильно помогают избежать кусания локтей.
ла-ла-ла
КЛ>>при чем здесь вообще апи, когда мы говорим про то, как делать секьюрити внутри? S>С чего это вдруг? S>Мы всю дорогу говорили именно про то, как должен выглядеть API снаружи. То, что там внутри, в первую очередь определяется контрактом протокола, затем — общей архитектурой решения. А уже дальше идут подробности реализации. Собственно, спор-то и идёт о том, то ли выставлять наружу 1 ресурс, схема которого сложным образом зависит от погоды на Венере, то ли выставлять наружу N ресурсов с предсказуемыми схемами.
ты сам себе противоречишь. невозможно говорить про апи без того, зачем он такой нужен. мы тут не про форму, а про сочетание ее с сожержанием
КЛ>>домыслы S>А то. Основанные на многолетнем опыте проектирования, изготовления, и использования различных сервисов
ну, люди много лет умудряются делать всякую фигню, это не показатель.
КЛ>>дорогостоящий саппорт? дороже разработки? S>Естественно. Потому что разработка делается 1 раз, а саппорт — всю жизнь. Вы себе представляете себестоимость 1 инцидента в саппорте?
всю жизнь? да твой код будет переписан через пару лет. сколько стоит индийский саппорт? представляю. но не надо мне зубы заговаривать — тейк про баги
в моем коде это спекуляция
КЛ>>ваши роли в субд и есть часть пермиссий через субд S>Какая-то путаница. У меня нет никаких "ролей в СУБД".
ну у тебя там есть юзер, у которого явно есть роль или зачем там была написана вся та бесполезная портянка
КЛ>>а что тогда надо использовать в твоем случае? S>Запросы. S>Пишем S>
S> IQueryable<OutboundInvoice> InvoicesSentBy(CompanyID currentCompany) =>
S> from i in db.OutboundInvoices where i.originator = currentCompany select i;
S> IQueryable<InboundInvoice> InvoicesSentTo(CompanyID currentCompany) =>
S> from i in db.InboundInvoices where i.destination = currentCompany select i;
S>
S>Всё. Поверх этого в контроллере проверяем, что у текущего пользователя есть пермиссия на доступ к InboundInvoices/OutboundInvoices. Всё.
в контроллере? ты серьезно? вот это ты гений проектирования безопасных приложений — поля отрезаем декларативно через поля в объекте (твой факторинг), пермиссии проверяем в контроллерах (кстати как?). такое где-то работает да — в очень простых системах.
это читерство. у тебя одна таблица, а не две. зачем сюда писать какой-то детский сад?
КЛ>>даже не буду комментировать, причем тут несколько сервисов и их взаимодействие я не понимаю, это вне контекста нашего обсуждения S>Это очень странно. Топик называется "помогите спроектировать микросервисное приложение". Как мы ухитрились выкинуть из контекста API для взаимодействия между микросервисами? S>И что тогда вообще осталось в контексте?
какая разница как называется топик, когда эта ветка давно уже про rest levels?
КЛ>>кто так вообще делает? выглядит как полная дичь если честно S>Я не знаю. Но если вы вдруг захотите применить Row Level Security из любой СУБД, в которой она есть, вам так и придётся делать.
у тебя windows головного мозга
КЛ>>>>select * from rows r КЛ>>>>join rows_perms p on r.id = p.r_id КЛ>>>> where p.perm = 'row_read' and p.user_id = :userid S>>>Прекрасно. Вы себе представляете производительность такого решения? Когда у нас табличка на пару миллионов строк, и есть тысяча пользователей с частично пересекающимися правами на эти строки?
КЛ>>да, индекс на rows_perms.user_id и будет быстро, S> Ну ок.
КЛ>>плюс там еще в 99 процентах будет предикат на индексированное поле как часть фильтра поискового запроса. S>И это всё ещё будет медленнее, чем прямой поиск по предикату, который применяется к единственной таблице (см. пример кода с Invoices выше).
да да, а твои проверки row-level секьюрити в контроллере стоят ноль да? и ты поташищь весь резалтсет для всех юзеров из базы да?
и пейджинг от этого у тебя не будет работать
КЛ>>да, часто данные для всех лежать в одной таблице и когда нужен row-level security у тебя просто нет выбора. либо копии данных (твои views видимо) либо так. S>Эмм, views никаких "копий данных" не создают. Если хотите — могу рассказать, как они работают.
да ты тут уже нарассказывал
S>Да, если вам некомпететный продакт навязал вот эту вот модельку "кому угодно можно выдавать доступ на что угодно", то выбора действительно нет. Ну, точнее, даже там бывают возможности поиграть с оптимизацией, но не очень большие. Тут вопросов нет. Вопрос как раз в том, как проектировать API, чтобы вот таких вот необходимостей не возникало.
ну спроектируй тут, только без хаков с db.OutboundInvoices, db.InboundInvoices — одна таблица, row-level security и тп. я тебе набросал _примерную_ схему, ты
же мне ответил "недостаточно вводных данных".
КЛ>>но это на запрос коллекции, а на запрос одного ресурса вообще все быстро потому что индекс и на rows_perms.id S>
ну смейся
КЛ>>первый пример довольно универсален, он иллюстрирует подход "на основании токена фильтруем резалтсет и тп" S>Нет конечно. В первом примере нет решительно никакой возможности управлять видимостью отдельных атрибутов на уровне отдельных объектов.
это уже хоть что-то для иллюстрации. у тебя же нет вообще ничего
КЛ>>а в твоем случае как? у тебя же схема прибита гвоздями S>Во-первых, в моём случае этого не надо, т.к. я против самой идеи разделять доступ "по-объектно". Это ухудшает сразу примерно всё: и эффективность, и безопасность, и удобство использования.
а, ну да. теперь понятно какие ты там приложения годами делаешь
S>Во-вторых, если даже нам такое припёрло, у меня состав заказанных полей известен в момент получения запроса, и мне не надо пытаться "доставать всё, для чего довольно пермиссий", с риском достать что-то не нужное или неожиданное.
какая чушь
S>Это гораздо надёжнее, чем пытаться перебирать все комбинации пермиссий и смотреть, какой получится результат.
это все слова, которые ты не готов обратить в код
КЛ>>сколько раз мы уже это слышали по поводу всего. похоже на отмазку для неадекватного задаче решения S>Как скажете.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Константин Л., Вы писали:
S>Если мне вдруг приезжает массив, где у каких-то объектов нет senderName, то это нарушает приведённую здесь спецификацию типа.
охо-хо, ну-ну. спецификацию типа
S>Можно, конечно, принудительно приписать вопросики ко всем свойствам этого интерфейса, и написать обработку в приложении на каждый такой случай, но это, скажем так, непрактично.
это, скажем так, реальность
S>А вот если мне приезжает массив, в котором не 100, а 10, или 0 элементов, инвариант сохранён. Я в любом случае не ожидаю, что мне вернётся ровно 100 элементов.
какая-то чушь
КЛ>>ну у нас так же, в чем поинт? S>Не знаю, как "у вас", а у исходного оппонента, судя по всему, в JSON будет список не ссылок, а объектов, причём состав объектов произвольно зависит не от самих объектов или аргументов запроса, а от наличия в токене тех или иных пермиссий.
аа, понял. конечно будет список объектов с ссылками, который зависит от аргументов запроса и от наличия в токене тех или иных пермиссий (только не обязательно в токене , можно же и без jwt а в базе посмотреть или что-то иное).
кому нужен пустой список только с ссылками? на вебе его не покажешь. будут легкие объекты и ссылки если надо взять конкретный полный.
КЛ>>смешно S>А вы всегда проектируете безопасность на основании описаний вроде "у нас есть пять типов отчётов, один из них внутренний, другой внешний". Вам сразу всё понятно, и можно бежать нарезать таблички в базе?
а вы всегда бегаете по форумам с заявлениями (цитирую) "Во-первых, в моём случае этого не надо, т.к. я против самой идеи разделять доступ "по-объектно"".
То есть вы проектируете так — "знаете, я выяснил требования и учел вероятные будущие изменения и я против".
S>Я раньше и сам выяснял подробности проекта на основании телепатии и ясновидения, но лет 15 тому мне их за неуплату отключили, поэтому я предпочитаю проектировать на основании установленных фактов, а также вероятных будущих изменений.
какой-то бред
КЛ>>да не, по сути он дает тебе query language к базе S>По сути там вообще может не быть никакой базы.
а по факту в 99 случаев она там есть
КЛ>>отвечай! S>Зависимость от контекста называется "модальностью" и является одним из признаков плохого проектирования. Такой зависимости нужно по возможности избегать.
то, что ту тут пишешь умные термины из преподавательской жизни лучше не делает. вернись в реальность
S>Если уж никак-никак от неё избавиться не удалось, нужно факторизовывать пространство состояний для этого контекста. И следить за тем, чтобы факторизация была корректной, т.е. изоляция между ортогональными классами состояний должна сохраняться.
мне кажется я начинаю понимать, откуда такой казеный язык и нажим на систему типов — многолетнее преподавание и .net?
S>Успешная факторизация позволяет нам перейти от K*M тестов к K+M тестам. Всё.
ага, а на практике "я против самой идеи разделять доступ "по-объектно"", "недостаточно данных для проектирования", "проверим пермиссии в контроллере", "по таблице на инвойс".
КЛ>>ну начинается! отлыниваешь ) S>Если вы хотите конструктивного обсуждения, можно попытаться взять какую-нибудь практическую задачу и посмотреть, как её решать в стиле REST — как с помощью микросервисов, так и без оных.
мне неинтересны микросервисы. я тебе в другой ветке дал юзкейс, ты отказался по нему что-то комментировать
S>Можно попытаться понять, ради чего вообще может в голову прийти "выставлять наружу псевдо-бд", и как это делать правильно, и чем это отличается от неправильного решения.
да мне это все неинтересно, потмому что в 99 случаев я против выставления хоть правильно, хоть неправильно. да и в "правильно" я не верю jfyi
Здравствуйте, Константин Л., Вы писали:
КЛ>PUT без параметров?
С параметрами, которые GET вернул. Структура ресурса не должна зависеть от метода
КЛ>а если ссылки поменялись между GET и PUT? "и вообще конкурентные обновления" — какие ужасы ты пишешь
А ты дизайни систему так, чтобы ссылки не менялись между GET и PUT. Идемпотентность, версии объекта и все дела. Ссылки не отменяют, а дополняют коды ошибок.
Здравствуйте, Sinclair, Вы писали:
S>Можно, конечно, принудительно приписать вопросики ко всем свойствам этого интерфейса, и написать обработку в приложении на каждый такой случай, но это, скажем так, непрактично.
Вполне практично, в Swagger спеке ты так или иначе должен для каждого поля указать обязательное оно или опциональное. И, соответственно, в имплементации обработать все случаи. У тебя не может быть такой ситуации, когда поле обязательное, а сервер его по какой-то причине не отдает. По-хорошему, у тебя даже код не должен скомпилироваться.
Здравствуйте, Miroff, Вы писали:
M>Здравствуйте, Константин Л., Вы писали:
КЛ>>PUT без параметров?
M>С параметрами, которые GET вернул. Структура ресурса не должна зависеть от метода
контракт на базе возвращаемых полей для конкретного инстанса ресурсы, а не на основе сваггера?
это ты какой-то очень простой crud описываешь. а что если мне надо заполнить пустое поле, которого нет в GET? или ты всегда
null возвращаешь для всех полей? допустим
КЛ>>а если ссылки поменялись между GET и PUT? "и вообще конкурентные обновления" — какие ужасы ты пишешь
M>А ты дизайни систему так, чтобы ссылки не менялись между GET и PUT. Идемпотентность, версии объекта и все дела. Ссылки не отменяют, а дополняют коды ошибок.
ты пишешь "Правильно делать GET перед PUT, потому что ссылки могут измениться, и вообще конкурентные обновления. ".
так вот между GET и PUT ты залил на сервер новую версию, клиент при этом не в курсе и держит у себя в текущем состоянии твой старый PUT.
Твои действия? меняешь версию апи в url и PUT идет на старый url?
"вообще конкурентные обновления" — что это значит в контексте ссылок, раскрой тему
Здравствуйте, gandjustas, Вы писали:
G>Поэтому MSA это техническое решение, а организационное. Если у вас много команд, каждая со своим подходом, технологическим стеком, архитектурой итд, то подружить их в рамках монолитного приложения будет технически невозможно.
У Линуса получилось. Ядро линукса это монолит. Лично я считаю, что МСА возникла от нехватки времени на тщательное проектирование. В текущих бизнес процессах никто не хочет давать время на проектирование и перепроектирование кода и процессов в командах. Поскольку это слабо предсказуемые и сложно планируемые активности, а ЛПР хотят понимать, что происходит и не готовы просто доверять технарям по вполне понятным человеческим причинам. Ну или это очень одаренные ЛПР.
Так как у меня было несколько возможностей самому принимать решения по крупным продуктам, скажу, что это может на порядки (не побоюсь этого слова) снижать стоимость решений. Но если бы я не умел делать это сам, не представляю как такой опыт можно повторить.
Ну и самое здесь интересное, что даже хороший, качественный монолит, разрабатываемый несколькими командами все равно крайне дорог и никто не способен представить, сколько бы стоила поддержка и такая же скорость доработок в МСА.
Например есть опердень на котором работает более тысячи организаций и несколько сотен тысяч человек (не менее сотни тысяч в день). За тысячу форм, процессов и отчетов, интеграции с десятками других систем. И этот монолит способен развиваться и поддерживаться командой в составе которой один программист, годовой бюджет которой единицы миллионов для заказчика. Коллеги, как думаете, насколько счастлив заказчик, что для него это все настолько дешево? Про счастье этого незаменимого программиста я тоже боюсь писать.
Здравствуйте, Ziaw, Вы писали:
Z>Здравствуйте, gandjustas, Вы писали:
G>>Поэтому MSA это техническое решение, а организационное. Если у вас много команд, каждая со своим подходом, технологическим стеком, архитектурой итд, то подружить их в рамках монолитного приложения будет технически невозможно.
Z>У Линуса получилось. Ядро линукса это монолит.
Угу, модульный монолит. Лучшая архитектура по балансу изоляции и накладных расходов. Но ядро линукса очень стабильно и цикл разработки у него не так, как у бизнес-приложений
Z>Лично я считаю, что МСА возникла от нехватки времени на тщательное проектирование. В текущих бизнес процессах никто не хочет давать время на проектирование и перепроектирование кода и процессов в командах. Поскольку это слабо предсказуемые и сложно планируемые активности, а ЛПР хотят понимать, что происходит и не готовы просто доверять технарям по вполне понятным человеческим причинам. Ну или это очень одаренные ЛПР.
Много причин использования МСА, далеко не все они оправданы с точки зрения экономики.
КЛ>задача ограничения доступа это и есть по сути то, что решают пермиссии. то есть ответ да, просто ты не понимаешь уже что пишешь
Нет, но я не совсем понимаю, что мне пишете вы. Да, теперь понятно — ответ "да".
КЛ>ла-ла-ла
КЛ>ты сам себе противоречишь. невозможно говорить про апи без того, зачем он такой нужен.
Ну так мы про это и говорим, а вы вдруг начинаете "при чём тут АПИ"
КЛ>ну, люди много лет умудряются делать всякую фигню, это не показатель.
Отож.
КЛ>всю жизнь? да твой код будет переписан через пару лет. сколько стоит индийский саппорт? представляю. но не надо мне зубы заговаривать — тейк про баги
Не было никакого тейка про баги. Я, наверное, плохо объяснил сценарий.
Вот у нас есть какая-нибудь экзотическая пермиссия на атрибут "НДС". Зачем? Да низачем. Просто пришёл в своё время суперуверенный в себе архитект, и набросал "универсальное RBAC-решение на все времена". На практике следуюшие 10 лет никто не задурялся настройкой этой пермиссии, потому что нафиг никому не упёрлись инвойсы без атрибута НДС. Нет такого бизнес-сценария.
Внешние разработчики, которые писали интеграцию с этим АПИ, всегда видели этот атрибут в JSON. Да и в OpenAPI спецификации этот атрибут приведён. Где-то, в какой-то доке, наверное, кто-то упомянул, что этот атрибут требует пермиссию Invoice.VAT.Read для конкретного инвойса. Но поскольку доки никто не читает, а в тестах интеграция работало в 100% случаев, этот сторонний сервис выкачен в эксплуатацию.
И вот ещё через несколько лет какой-нибудь шибко активный админ решает поубирать у какого-нибудь пользователя "лишние" пермиссии на какие-то отдельные объекты.
Пользователь выполняет свой привычный workflow, и внезапно обнаруживает 500 internal error. Потому что сервису вдруг попался экземпляр инвойса с атрибутом НДС=null, а на это никто не рассчитывал.
КЛ>ну у тебя там есть юзер, у которого явно есть роль или зачем там была написана вся та бесполезная портянка
Я вроде три раза объяснил, в четвёртый уже не буду.
КЛ>в контроллере? ты серьезно? вот это ты гений проектирования безопасных приложений — поля отрезаем декларативно через поля в объекте (твой факторинг), пермиссии проверяем в контроллерах (кстати как?). такое где-то работает да — в очень простых системах.
Ну, научите же меня, как всё это правильно делать. А то по моей практике, простые решения — они самые надёжные.
КЛ>это читерство. у тебя одна таблица, а не две. зачем сюда писать какой-то детский сад?
Да, у меня одна таблица. Читерство-то в чём? Детский сад — это ваша манера общаться. Я что-то начал от неё уставать.
КЛ>какая разница как называется топик, когда эта ветка давно уже про rest levels?
Прекрасно.
КЛ>у тебя windows головного мозга
Windows тут ни при чём. Row-level security в каком-нибудь Постгрес устроены ровно так же.
Пример, который я привёл, про этот сайт — поэтому упомянут Windows и SQL Server.
КЛ>да да, а твои проверки row-level секьюрити в контроллере стоят ноль да? и ты поташищь весь резалтсет для всех юзеров из базы да?
Вот зачем вы пишете бред. Я же показал вам тремя абзацами выше код запросов — где там "весь резалтсет для всех юзеров из базы"?
КЛ>и пейджинг от этого у тебя не будет работать
Прекрасно он будет работать.
КЛ>да ты тут уже нарассказывал
Я как-то не рассчитывал встретить в архитектурной дискуссии незнание основ RDBMS. Поэтому надеюсь на то, что я просто вас не так понял. Но, на всякий случай выражаю готовность поделиться всем, что знаю сам.
КЛ>ну спроектируй тут, только без хаков с db.OutboundInvoices, db.InboundInvoices — одна таблица, row-level security и тп.
Непонятно, что такое "хаки".
КЛ>я тебе набросал _примерную_ схему, ты КЛ>же мне ответил "недостаточно вводных данных".
Вы жульничаете. Схему вы набросали про фильтрацию строк, а задачу, про которую я ответил "недостаточно данных" — про какую-то (непонятно какую) обрезку атрибутов.
И ни в одном из случаев нет ничего про постановку задачи. Выглядит так, что вы стараетесь сначала придумать решение, а уже потом любой ценой его защитить, вообще не задумываясь, а зачем такое решение нужно.
КЛ>ну смейся
А то.
КЛ>какая чушь
Не, беру свои слова по поводу "поделиться всем, чем знаю" обратно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, gandjustas, Вы писали:
G>Угу, модульный монолит. Лучшая архитектура по балансу изоляции и накладных расходов. Но ядро линукса очень стабильно и цикл разработки у него не так, как у бизнес-приложений
Про лучший вариант архитектуры соглашусь. Если взять что-то сравнимое по сложности, типа Яндекс 360, то релизный цикл похожий. Более того, подозреваю, что именно микросервисная архитектура этого изделия сделала невозможной его доводку до приличного состояния. То же можно сказать и про интерфейс яндекс облака, там уши всяких узкосервисных проблем торчат регулярно, но там хотя бы бабло идет. Интересно, есть тут кто-то близкий к этим командам Яндекса, чтобы прокомментировать.
G>Много причин использования МСА, далеко не все они оправданы с точки зрения экономики.
Я могу назвать только одну — борьба со сложностью, но, имхо, это фикция. На уровне конечного продукта сложность возрастает. Иногда мне кажется, что на это всем пофиг, главное работой обеспечены.
Здравствуйте, Miroff, Вы писали:
M>Здравствуйте, Константин Л., Вы писали:
КЛ>>это ты какой-то очень простой crud описываешь
M>Именно! В этом и смысл REST, выражать сложную логику через очень простой CRUD
Здравствуйте, Sinclair, Вы писали:
S>Нет, но я не совсем понимаю, что мне пишете вы. Да, теперь понятно — ответ "да".
ну так ведь это же даже не секьюрити а костыль.
S>Не было никакого тейка про баги. Я, наверное, плохо объяснил сценарий.
[] S>Пользователь выполняет свой привычный workflow, и внезапно обнаруживает 500 internal error. Потому что сервису вдруг попался экземпляр инвойса с атрибутом НДС=null, а на это никто не рассчитывал.
вы ошибку использования переносите на ошибку проектирования. придумали какой-то вырожденный случай чтобы под него подогнать свои пристрастия в ахитектуре.
я тоже люблю когда просто. но делать секьюрити через скрывание полей факторизацией это не секьюрити
КЛ>>ну у тебя там есть юзер, у которого явно есть роль или зачем там была написана вся та бесполезная портянка S>Я вроде три раза объяснил, в четвёртый уже не буду.
я реально не понял, видимо потмоу что мне в голову такое не приходило делать
S>Ну, научите же меня, как всё это правильно делать. А то по моей практике, простые решения — они самые надёжные.
простые — да. но мир сложен. учим вот но ты ни в какую)
КЛ>>это читерство. у тебя одна таблица, а не две. зачем сюда писать какой-то детский сад? S>Да, у меня одна таблица. Читерство-то в чём? Детский сад — это ваша манера общаться. Я что-то начал от неё уставать.
я тоже, сори
КЛ>>у тебя windows головного мозга S>Windows тут ни при чём. Row-level security в каком-нибудь Постгрес устроены ровно так же. S>Пример, который я привёл, про этот сайт — поэтому упомянут Windows и SQL Server.
какой сайт? rsdn? ужас.
Вы писали "Это когда мы заводим для пользователя №44487 виндовый аккаунт, даём этому аккаунту права на SQL базу с табличками forums, topics, replies, и marks, при логине на сайт создаём виндовую сессию, и все запросы в SQL Server выполняем через новое соединение под правами этого виндового аккаунта."
в постгрес так никто делать не будет в здравом уме
КЛ>>да да, а твои проверки row-level секьюрити в контроллере стоят ноль да? и ты поташищь весь резалтсет для всех юзеров из базы да? S>Вот зачем вы пишете бред. Я же показал вам тремя абзацами выше код запросов — где там "весь резалтсет для всех юзеров из базы"?
а где там фильтрация по юзеру? Это:
IQueryable<OutboundInvoice> InvoicesSentBy(CompanyID currentCompany) =>
from i in db.OutboundInvoices where i.originator = currentCompany select i;
IQueryable<InboundInvoice> InvoicesSentTo(CompanyID currentCompany) =>
from i in db.InboundInvoices where i.destination = currentCompany select i;
КЛ>>да ты тут уже нарассказывал S>Я как-то не рассчитывал встретить в архитектурной дискуссии незнание основ RDBMS. Поэтому надеюсь на то, что я просто вас не так понял. Но, на всякий случай выражаю готовность поделиться всем, что знаю сам.
ты про то, что я написал views вместо materialized views? жестко
КЛ>>ну спроектируй тут, только без хаков с db.OutboundInvoices, db.InboundInvoices — одна таблица, row-level security и тп. S>Непонятно, что такое "хаки".
разбиение на 2 таблицы, потому что по коду неочевидно, что у тебя одна таблица
КЛ>>я тебе набросал _примерную_ схему, ты КЛ>>же мне ответил "недостаточно вводных данных". S>Вы жульничаете. Схему вы набросали про фильтрацию строк, а задачу, про которую я ответил "недостаточно данных" — про какую-то (непонятно какую) обрезку атрибутов. S>И ни в одном из случаев нет ничего про постановку задачи. Выглядит так, что вы стараетесь сначала придумать решение, а уже потом любой ценой его защитить, вообще не задумываясь, а зачем такое решение нужно.
да я просто рассказываю что я видел в своей практике
КЛ>>какая чушь S>Не, беру свои слова по поводу "поделиться всем, чем знаю" обратно.
"Вот зачем вы пишете бред." — твои слова выше. Но согласен, я мог бы и помягче, сори
Здравствуйте, Константин Л., Вы писали:
КЛ>ну так ведь это же даже не секьюрити а костыль.
Хотелось бы более внятных обоснований такого утверждения.
КЛ>вы ошибку использования переносите на ошибку проектирования.
Подобное проектирование означает "давайте я не буду разбираться в сценариях пользователя, а перевалю ответственность за них на тех, кто моё творение будет эксплуатировать". Примерно так же, как "настраиваемый пользователем
гуй". Да, бывают ситуации, когда мы не можем заранее спроектировать все нужные сценарии — потому что собственно поставляем не приложение, а конструктор.
Но это не потому, что это хорошая практика — это вынужденное решение. Есть возможность его избежать — надо его избегать.
КЛ>простые — да. но мир сложен. учим вот но ты ни в какую)
Я подозреваю, что на самом деле мы говорим об одном и том же, только разными словами.
КЛ>я тоже, сори
КЛ>Вы писали "Это когда мы заводим для пользователя №44487 виндовый аккаунт, даём этому аккаунту права на SQL базу с табличками forums, topics, replies, и marks, при логине на сайт создаём виндовую сессию, и все запросы в SQL Server выполняем через новое соединение под правами этого виндового аккаунта." КЛ>в постгрес так никто делать не будет в здравом уме
И нигде не будет. Этот подход придуман в SQL-92, расширен в SQL-99, и примерно тогда же устарел навсегда.
Я приводил его как пример применения принципа, который был уместен в клиент-серверных приложениях эпохи девяностых.
Сейчас технологическая основа изменилась, а принципы — нет.
Вместо "таблицы" у нас "микроссервис с сырыми данными", вместо "хранимой процедуры" или "представления" у нас "микросервис фасада", а в остальном всё так же и есть.
Оппонент предлагает таскать токен внешнего пользователя сквозь всю иерархию сервисов — типа я обращаюсь к микросервису "invoices", а тот, в свою очередь, бежит за подробностями отправителя инвойса к микросервису "counteragents", отдавая туда мой же токен. И вот тут-то у нас и возникает чудо голодания: микросервис "counteragents" возвращает ему 403/404, если у меня нет привилегии смотреть запрошенного контрагента. И, соответственно, фасадный микросервис отдаёт мне инвойс без атрибута sender.
Я пытаюсь объяснить, что такое решение не вполне удачно.
КЛ>а где там фильтрация по юзеру? Это:
КЛ>
КЛ> IQueryable<OutboundInvoice> InvoicesSentBy(CompanyID currentCompany) =>
КЛ> from i in db.OutboundInvoices where i.originator = currentCompany select i;
КЛ> IQueryable<InboundInvoice> InvoicesSentTo(CompanyID currentCompany) =>
КЛ> from i in db.InboundInvoices where i.destination = currentCompany select i;
КЛ>
Да. В исходной задаче не было никакого требования "разделять инвойсы по конкретным пользователям". В 99% случаев такого бизнес-сценария вовсе нет.
Например, на сайте RSDN нет никаких ручек для выдачи произвольным пользователям произвольных пермиссий на конкретные сообщения. И ничего, за 25 лет никто не умер от этого.
Так и тут — мы провели анализ предметной области, выяснили сценарии пользователей, и обнаружили, что нужно всего два набора пермиссий — на "инвойсы, выставленные компанией, где пользователь работает", и на "инвойсы, полученные компанией, где пользователь работает". (Это ещё сложный случай, сервис для B2B взаимодействия. Если мы пилим сервис P2P, то там модель безопасности будет ещё проще).
Откуда взялись эти наборы пермиссий? Да из того, что в исследованных нами компаниях-клиентах встречаются следующие случаи:
1. One person does all accounting
2. One department does all accounting
3. There are accounts payable and accounts receivable departments
Случаев "право оплатить конкретный один инвойс нам нужно назначить одному конкретному сотруднику" мы обнаружить не смогли, как ни старались.
Тем более у нас не нашлось случаев "надо выдать доступ к каким-то инвойсам, выставленным компанией X компании Y, сотруднику какой-то посторонней компании Z"
Поэтому мы делаем так, как описано в коде выше.
И это обеспечивает одновременно высокую безопасность (нет возможности напороть с настройками при эксплуатации), высокую производительность (все поисковые запросы можно ускорить путём построения подходящих индексов), и высокое удобство пользования.
На всякий случай, если непонятно: вот у нас сотрудник компании X (с соответствующими правами) выставляет инвойс компании Y.
Этот инвойс виден всем уполномоченным сотрудникам компании X, а особо уполномоченные могут даже его отзывать и редактировать.
Но с момента, когда он переведён в статус "отправлен получателю", он должен стать виден всем уполномоченным сотрудникам компании Y.
Я с удовольствием посмотрю, как вы эту задачу решите в вашей модели безопасности.
КЛ>ты про то, что я написал views вместо materialized views? жестко
Я вообще не понимаю, откуда в рассуждениях взялись materialized views.
КЛ>разбиение на 2 таблицы, потому что по коду неочевидно, что у тебя одна таблица
Ну хорошо, давайте поговорим об этом подробнее.
public class PaypalDb : LinqToDB.Data.DataConnection
{
public PaypalDb() : base("everything") { }
public ITable<OutboundInvoice> OutboundInvoices => this.GetTable<OutboundInvoice>();
public IQueryable<InboundInvoice> Category => from oi in this.OutboundInvoices select Mapper<OutboundInvoice, InboundInvoice>.DefaultMapper.Map(oi);
// ... other tables ...
}
Если бы речь шла не о дотнете, а о чём-то более убогом, то я бы, наверное, создал в БД
create view InboundInvoices as
select
originator,
originatorName,
amount,
sentDate,
status
expirationDate,
destination,
destinationName,
amount,
amountVAT
from Invoices
КЛ>да я просто рассказываю что я видел в своей практике
Отлично.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Miroff, Вы писали:
M>Именно! В этом и смысл REST, выражать сложную логику через очень простой CRUD
Именно поэтому у Paypal — не REST.
На основе их API, вы никак не можете "сделать GET" на рефанд, потому что у них рефанд — это POST на магический урл.
И никто вам параметров этого рефанда не подскажет, кроме, собственно, документации.
А если у вас есть документация, то вам нафиг не упала ссылка на рефанд в каждом пейменте. Вы и так поймёте, куда нужно отправить те параметры, которые описаны в документации.
Вообще, первый REST API, в разработке которого я участвовал, был устроен как раз примерно так.
Только мы были ещё более радикальны: в зависимости от того, какое расширение было в конце запрошенного URL (.xml, .json, .html), отдавалось разное представление ресурса.
И вот в HTML представлении в тех местах, откуда можно было делать параметризованные запросы (включая POST), приезжала форма с полями и соответствующим action.
И если у параметров было конечное количество значений, то они там в input type=select указывались.
Так что по API можно было бродить обычным браузером. HATEOASнее уже некуда.
Даже и не помню, какой это был год. Наверное, что-то вроде 2008 или 2009.
Потом оказалось, что нафиг это всё никому не упало.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Ziaw, Вы писали:
G>>Угу, модульный монолит. Лучшая архитектура по балансу изоляции и накладных расходов. Но ядро линукса очень стабильно и цикл разработки у него не так, как у бизнес-приложений Z>Про лучший вариант архитектуры соглашусь. Если взять что-то сравнимое по сложности, типа Яндекс 360, то релизный цикл похожий. Более того, подозреваю, что именно микросервисная архитектура этого изделия сделала невозможной его доводку до приличного состояния. То же можно сказать и про интерфейс яндекс облака, там уши всяких узкосервисных проблем торчат регулярно, но там хотя бы бабло идет. Интересно, есть тут кто-то близкий к этим командам Яндекса, чтобы прокомментировать.
А зачем сравнивать ядро линукса и современные бизнес-приложения (вернее бизнес-сервисы)? У них же разная, скажем так, архитектурная топология. Бизнес-сервисы это уже распределенные системы как минимум по причине наличия БД.
я понял, dto/so на роль, вьюха на роль и все. и мы приходим к первоначальному конфликту — такое не работает, когда ролей много, когда нужны fine-grained permission etc. В смысле, не работает только у нас, у тебя — работает!
Здравствуйте, Константин Л., Вы писали:
КЛ>я понял, dto/so на роль, вьюха на роль и все. и мы приходим к первоначальному конфликту — такое не работает, когда ролей много, когда нужны fine-grained permission etc. В смысле, не работает только у нас, у тебя — работает!
Вы сначала расскажите, что за задача. А там уже можно обсуждать, какие решения лучше, а какие — хуже.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.