Аутентификация vs авторизация

Аутентификация и авторизация: «кто ты» против «что тебе можно».

Суть: аутентификация устанавливает личность пользователя (кто он), авторизация решает, что ему разрешено делать. Это два разных шага: сначала узнаём пользователя, потом проверяем его права.

Эти слова часто путают, но разница принципиальна. Аутентификация — это вход (логин/пароль, токен): система убеждается, что вы тот, за кого себя выдаёте. Авторизация — это контроль доступа: даже залогиненный пользователь не имеет права удалять чужие данные, если он не админ.

Два понятия

АспектАутентификацияАвторизация
ВопросКто ты?Что тебе можно?
КогдаПервойПосле аутентификации
РезультатЛичность (Claims)Доступ разрешён/запрещён
ПримерПроверка токенаПроверка роли Admin

Claims — кирпичики личности

После аутентификации пользователь представлен набором claims (утверждений): «Id = 42», «Email = [email protected]», «Role = Admin». Авторизация принимает решения, читая эти claims.

Запрос с токеном
      |
      v
[Authentication] токен валиден? -> да -> Claims: { id:42, role:Admin }
      |                              нет -> 401 Unauthorized
      v
[Authorization] нужна роль Admin? -> есть -> пропустить
                                      нет  -> 403 Forbidden
      |
      v
[Эндпоинт]

Как работает под капотом

Middleware UseAuthentication читает учётные данные из запроса (например токен из заголовка), проверяет их и, если всё верно, наполняет HttpContext.User объектом ClaimsPrincipal с claims. Дальше UseAuthorization и атрибуты [Authorize] читают этот User и сверяют с требованиями (нужна роль/политика). Важно различать коды: 401 Unauthorized — «ты не представился» (нет/плохой токен), 403 Forbidden — «представился, но прав не хватает».

Частые ошибки

  • Путать 401 и 403. 401 — не аутентифицирован, 403 — аутентифицирован, но нет прав. Возврат не того кода путает клиентов.
  • Авторизация на фронтенде «вместо» бэкенда. Скрытая кнопка не защита — проверку прав делает сервер.
  • Считать, что логин равен полному доступу. Аутентификация не отменяет проверку прав на каждое действие.

Best practices

  • Чётко разделяйте два шага и ставьте middleware в правильном порядке (Authentication, затем Authorization).
  • Стройте авторизацию на claims/политиках, а не на разбросанных по коду условиях.
  • Защищайте каждый чувствительный эндпоинт явно — «по умолчанию закрыто» безопаснее.

Claims, схемы и единый ClaimsPrincipal

После успешной аутентификации пользователь в ASP.NET Core представлен объектом ClaimsPrincipal — набором claims (утверждений вида «ключ-значение»): идентификатор, имя, email, роли, любые кастомные атрибуты. Этот объект лежит в HttpContext.User и доступен всему конвейеру и эндпоинтам. Авторизация не «логинит» заново — она читает уже готовые claims и сверяет их с требованиями. Такое разделение позволяет менять способ аутентификации (cookie, JWT, внешний провайдер) не трогая логику авторизации: она всегда работает с единым ClaimsPrincipal.

Способ аутентификации задаётся схемой: cookie-схема (классические веб-сайты с сессией в куке), JWT Bearer (stateless-API), OAuth/OpenID Connect (вход через Google, корпоративный SSO). Схем может быть несколько одновременно, и эндпоинт способен указывать, какая из них применима. Но на выходе у всех одно — наполненный ClaimsPrincipal.

Принцип наименьших привилегий и многоуровневая защита

Авторизацию строят по принципу наименьших привилегий: по умолчанию доступ закрыт, а открывается ровно то, что нужно конкретной роли или пользователю. Удобный приём — глобальный [Authorize] на всё приложение и точечные [AllowAnonymous] на публичные эндпоинты (логин, регистрация, health). Так невозможно «забыть» защитить новый чувствительный эндпоинт — он закрыт автоматически, пока вы явно не разрешите. Это сдвигает класс ошибок «случайно оставил открытым» из разряда возможных в разряд исключённых по конструкции.

Критично понимать, что авторизация на клиенте — это лишь удобство интерфейса, а не защита. Скрытая кнопка «удалить» не мешает отправить DELETE-запрос напрямую. Настоящая проверка прав происходит только на сервере, на каждом чувствительном действии. И различие кодов 401 (не аутентифицирован — иди представься) и 403 (аутентифицирован, но прав нет) — не формальность: по ним клиент выбирает, отправить пользователя на логин или показать «доступ запрещён». Возврат не того кода ломает это поведение.

Итог: аутентификация отвечает «кто ты», авторизация — «что можно»; они идут по порядку и оперируют claims. Дальше — как это реализуют через JWT-токены.

Проверьте себя
1. Чем аутентификация отличается от авторизации?
AЭто синонимы
BАутентификация устанавливает, кто пользователь; авторизация — что ему разрешено
CАвторизация идёт первой
DАутентификация проверяет роли
2. В чём разница между кодами 401 и 403?
AЭто одно и то же
B401 — не аутентифицирован (не представился), 403 — аутентифицирован, но прав не хватает
C401 — нет прав, 403 — нет токена
DОба означают успех