Защо междинният софтуер може да не е правилната абстракция за вашите политики за данни.

Писането на съвместими и сигурни бекендове е трудно. Ето какво правят разработчиците, за да направят този проблем по-управляем

Всеки фронтенд разработчик знае или поне подозира, че бекендовете са трудни. Но защо би било така?

Няма нищо присъщо трудно с бизнес логиката на бекенда: в края на краищата това са само код и алгоритми. Фъзбузът си е фъзбузз: еднакво безполезен в бекенда, както и във фронтенда.

Какво прави бекендовете по-трудни?

Бекендовете са трудни, защото се занимават директно с вашите данни, а данните имат изисквания, които надхвърлят манипулирането на данни, което искате да направите. Например:.

  • Кой има достъп до тези данни и при какви обстоятелства?
  • Къде могат да се съхраняват (и кешират) данните, за да отговарят на разпоредби като GDPR?
  • Съхранението на данни отговаря ли на всички регулации и изисквания на бизнеса? Например криптиран ли е когато и където трябва да бъде?

За да отделим ясно тази задача от задачата за кодиране на бизнес логиката на вашия бекенд, нека наречем това правила за данни, които бекендът трябва да приложи.

Начини за кодиране на съвместими с правилата бекендове

Прилагането на политики за данни може да бъде обезсърчително за разработчиците без пряк опит в тази област. А цената на грешките е огромна. Но ако трябва да го направите... трябва да го направите! И така, какви са някои от стратегиите, които човек може да използва, за да се справи с тези изисквания?

Един подход е да разпръснете логиката на правилата във вашия код. Всеки път, когато трябва да тествате дали някой е влязъл, кой е той, какво може да прави, просто добавете куп оператори if/else и сте готови!

Това има очевидни недостатъци: докато вашият код се развива, е трудно да се гарантира, че поради човешка грешка политиките за данни не се пропускат. Това не само е досадно, грешките са трудни за улавяне, особено в големи кодови бази, и в един момент данните ще избягат от границите на политиката.

Решение ли е междинният софтуер?

Другата алтернатива е да се използва общ модел в повечето рамки: мидълуер. Мидълуерът е код, който се изпълнява преди и/или след извикване на крайна точка и може да откаже заявката веднага, както и да трансформира изхода, за да съответства на правилата за данни.

Проблемът е, че междинният софтуер е свързан с вашата конкретна крайна точка. Освен това, за да позволят подреждане, те са непрозрачни и работят на границата на заявката/отговора.

Но през повечето време това, което наистина искате, е да защитите данните в текущия им контекст. Искате да можете да изразявате неща като

  • „ако потребителят е правилно удостоверен, нека вижда собствените си публикации. В противен случай ги скрийте"
  • „Ако тези лични данни са свързани с европейски потребител, съхранявайте ги на място в Европа“
  • „Уверете се, че тези данни преминават през криптирана връзка“

Прости срещу сложни крайни точки

За крайна точка, която докосва само една част от данните – например API за просто извличане на потребител по id, съпоставянето на политиката за данни към крайната точка все още е управляемо: разрешаването на крайната точка означава разрешаване на достъп до този потребител!

Но в момента, в който стане по-сложно, като например ако трябва да получите достъп до списък със задачи, за да решите кой потребител да извлечете, нещата стават по-сложни, тъй като политиките ви за данни може да са различни за всяка информация.

може също да не работи добре: междинният софтуер, особено ако трябва да посредничи между много типове данни, може да няма възможност да трансформира заявките. Работи непрозрачно върху заявката и отговорите.

Поради това междинният софтуер има тенденция да играе роля в неща като удостоверяване на потребителя и предоставяне на общ достъп до крайната точка. Но ефективният и безопасен достъп до данните все още се осъществява на ниво бизнес логика, като разработчиците трябва да се уверят, че заявките са правилно филтрирани, маскирани и трансформирани.

Това нарушава абстракцията на междинния софтуер и ние се връщаме на изходна позиция, като данните потенциално излизат от границите на политиката.

Нарушаване на абстракцията на междинния софтуер

За да разберем как се нарушава непрозрачната абстракция на междинния софтуер, нека да разгледаме примера за филтриране на данни: след като потребителят бъде удостоверен, контекстът на заявката, включително самоличността на потребителя, може да се използва за ограничаване на данните, до които потребителят има достъп.

Общите опции са: добавяне на филтри към кода на крайната точка, нарушаване на абстракцията на междинния софтуер или филтриране на резултата от междинен софтуер, преди резултатът да бъде върнат на потребителя. Последният е по-стабилен, тъй като ще оцелее при промени в крайните точки.

Но за да запазите високите си резултати в Lighthouse, често се предпочита нарушаването на абстракцията.

Друг пример е съответствието на данните: бази данни като Yugabyte, Mongo Atlas, CockroachDB, между другото, ви позволяват да зададете конкретни свойства на вашите редове, за да сте сигурни, че се съхраняват на конкретно географско местоположение и отговарят на закони като GDPR, CCPA и т.н.

Но особено за API, работещи с множество типове данни, манипулирането на данни и промяната на стойностите на редовете нарушава абстракцията на междинния софтуер.

Как политиките за данни могат да трансформират вашия бекенд

Много по-добър подход е да се позволи на разработчика да напише политики за данни, които се интегрират директно в бекенда и същевременно са достатъчно прости и изолирани, за да бъдат инспектирани по всяко време, което дава на разработчиците спокойствието, че правилата се прилагат.

Един пример за това е функцията за правила за данни в ChiselStrike, която вече е достъпна като функция за предварителен преглед в 0.13. В ChiselStrike базата данни е абстрахирана и всичко е първо TypeScript. Например, ето как бихте могли да моделирате потребителски обект:

Политиките за данни в ChiselStrike са наясно кой потребител е влязъл. Това се прави чрез стандартни JWT, които можете да получите от услуги като Okta или Clerk. Веднъж правилно дешифриран, JWT ще изглежда така:

След това можете да създадете изходен файл с име, съответстващо на защитения обект (policies/User.ts) със следното съдържание:

Първото нещо, което трябва да се отбележи за тези политики е, че те са централни и обвързани с данните. Можете да го инспектирате на едно място и да разсъждавате какво прави навсякъде във вашия бекенд.

В този пример никой никога не може да създаде потребителски обект, освен ако неговият потребителски идентификатор не съвпада със съдържанието на JWT. Това ще се прилага автоматично при всяко създаване на потребител. Подобни правила са налични и за операции за четене и актуализиране.

Правилата могат също да се използват за филтриране на екземпляри на обекти, които биха били върнати от заявка:

Интересното тук е, че компилаторът ChiselStrike инспектира всички файлове с правила и работи на ниво заявка, за да гарантира ефективност. В примера по-горе userId се добавя автоматично като филтър към входящи потребителски заявки. Данните, които не трябва да се виждат, никога не напускат базата данни.

Политиките за данни могат да направят много повече:

  • Използвайки политиката за създаване, можете да се уверите, че данните, които нямат определени полета или имат невалидни стойности, никога няма да бъдат записани в базата данни.
  • По същия начин политиките могат да маскират данни, например отказвайки достъп до определени полета. Например можете да посочите, че само влязъл потребител вижда собствената си лична информация или да я премахнете за заявки, произхождащи от някой друг.
  • Можете да трансформирате записи, преди да бъдат запазени: добавяне на полета, указващи географско разположение в бази данни, които го поддържат, и постигане на съответствие, или например съкращаване или стандартизиране на стойности.

Сега какво?

Първоначална версия на тази работа е налична в ChiselStrike 0.13 и ние работим за нейното стабилизиране. Цялата работа по това е на открито, в нашето хранилище GitHub.

Имате ли мисли за това? Ще се радваме да чуем как планирате да използвате това в нашия Discord или Twitter.