Авторизация — это не про код. Это про язык, на котором продукт описывает «кто что может». Если язык богатый и точный — код пишется почти сам. Если язык бедный — никакая библиотека не спасёт.

can(subject, action, resource)? Один сервис авторизации отвечает на этот вопрос, и три ловушки ролевой модели: роль как мешок прав, проверка размазана по коду, делегирование прикручивают последним

Что важно зафиксировать в начале

  • Кто такие subject и principal — и почему это не всегда один человек.
  • Что такое resource в твоей системе и как они вкладываются друг в друга.
  • Какие действия атомарны, а какие — композитные.

Дальше всё становится механикой: scopes ложатся на действия, роли — на наборы scopes, делегирование — на принципалов. Но если язык в начале размыт, эта механика будет разваливаться на каждом новом требовании.

Три ловушки, в которые я видел, как падают команды

  • Роль как мешок прав. «admin», «manager», «viewer» — и через год у тебя двадцать ролей, которые отличаются на одно действие. Роль должна быть именем для набора scopes, а не свалкой.
  • Проверка доступа размазана по коду. Если if user.role == 'admin' встречается в сорока местах — у тебя нет модели доступа, у тебя есть сорок мнений о ней. Решение одно: одна точка, которая отвечает на вопрос «можно ли subject сделать action над resource».
  • Делегирование прикручивают последним. «дай моему помощнику доступ от моего имени» — это не фича на потом, это меняет саму форму модели. Закладывай principal ≠ subject с первого дня.

Что мы выбрали

Ресурсо-ориентированную модель поверх OAuth2: scopes описывают действия над типами ресурсов, токен несёт scopes и subject, а проверка «этот subject над этим конкретным resource» живёт в одном сервисе авторизации, который дёргают все остальные. JWT — для stateless-проверки scope, обращение к сервису — когда нужно решение по конкретному объекту.

Хорошая модель доступа читается как предложение: «этот subject может выполнить это action над этим resource». Если описать конкретный кейс этим предложением не получается — модель ещё не готова.