В этой статье я расскажу, как реализовать авторизацию через ЕСИА.
Что такое ЕСИА
Единая система идентификации и аутентификации (ЕСИА) — информационная система в Российской Федерации, обеспечивающая санкционированный доступ участников информационного взаимодействия (заявителей и должностных лиц органов исполнительной власти) к информации, содержащейся в государственных информационных системах и иных информационных системах.
К основным функциональным возможностям ЕСИА относятся:
- идентификация и аутентификация пользователей;
- управление идентификационными данными;
- авторизация уполномоченных лиц органов исполнительной власти при доступе к функциям ЕСИА;
- ведение информации о полномочиях пользователей в отношении информационных систем.
ЕСИА предназначена для обеспечения:
- доступа пользователей к различным информационным системам без необходимости повторной регистрации на основе единых идентификационных параметров с использованием различных носителей: СНИЛС и пароль, электронная подпись, SIM-карта или смарт-карта;
- доступа должностных лиц государственных организаций к базовым ресурсам;
- осуществления идентификации и аутентификации должностных лиц органов исполнительной власти при межведомственном взаимодействии;
- взаимодействия информационных систем, то есть механизмов идентификации, аутентификации и авторизации информационных систем при взаимодействии с использованием СМЭВ.
Авторизация через ЕСИА
Для приготовления авторизации через ЕСИА нам понадобится сам nginx и его плагины encrypted-session, headers-more, auth_request, uuid4, set-misc, sign, jwt. (Я дал ссылки на свои форки, т.к. делал некоторые изменения, которые пока не удалось пропихнуть в оригинальные репозитории. Можно также воспользоваться готовым образом.)
Для начала зададим
1 |
encrypted_session_key "abcdefghijklmnopqrstuvwxyz123456"; |
(это необходимое условие работы плагина encrypted-session).
Дальше, на всякий случай, отключаем авторизационный заголовок
1 |
more_clear_input_headers Authorization; |
Теперь защищаем всё авторизацией
1 2 3 4 5 6 7 8 9 |
auth_request /auth; location =/auth { internal; set_decode_base64 $auth_decode $cookie_auth; # раскодируем авторизационную куку set_decrypt_session $auth_decrypt $auth_decode; # расшифровываем авторизационную куку if ($auth_decrypt = "") { return 401 UNAUTHORIZED; } # если не удалось расшифровать, то значит пользователь не авторизован more_set_input_headers "Authorization: Basic $auth_decrypt"; # подменить авторизацию на basic (чтобы использовать переменную $remote_user) echo -n OK; # пользователь авторизован } |
Для авторизованных пользователей показываем контент из их папки
1 2 3 |
location / { alias html/$remote_user/; } |
А при отсутствии авторизации перенаправляем на ЕСИА
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
error_page 401 = @error401; location @error401 { set $client_id мнемоника; # задаём мнемонику ЕСИА set $scope openid; # задаём запрашиваемые скоупы uuid4 $state; # генерируем случайное состояние set_formatted_local_time $timestamp "%Y.%m.%d %H:%M:%S %z"; # задаем дату-время в требуемом ЕСИА формате sign_certificate /data/nginx/esia.crt; # задаём сертификат (который мы загрузили в ЕСИА) sign_certificate_key /data/nginx/esia.key; # задаём приватный ключ sign_set $client_secret $scope$timestamp$client_id$state; # подписываем необходимые ЕСИА параметры set_escape_uri $access_type_escape online; # задаём необходимый ЕСИА способ доступа и кодируем его set_escape_uri $client_id_escape $client_id; # кодируем мнемонику set_escape_uri $client_secret_escape $client_secret; # кодируем подпись set_escape_uri $redirect_uri_escape $scheme://$server_name:$server_port/login; # задаём и кодируем адрес возврата set_escape_uri $response_type_escape code; # задаём и кодируем тип ответа set_escape_uri $scope_escape $scope; # кодируем скоупы set_escape_uri $state_escape $state; # кодируем состояние set_escape_uri $timestamp_escape $timestamp; # кодируем дату-время return 303 https://esia.gosuslugi.ru/aas/oauth2/ac?access_type=$access_type_escape&client_id=$client_id_escape&client_secret=$client_secret_escape&redirect_uri=$redirect_uri_escape&response_type=$response_type_escape&scope=$scope_escape&state=$state_escape×tamp=$timestamp_escape; # перенаправляем на ЕСИА |
После успешной авторизации пользователя в ЕСИА, его перенаправляет на адрес возврата
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
location =/login { auth_request off; # не использовать авторизацию auth_jwt_key /data/nginx/esia.pub file; # задаём публичный ключ (который мы получили от ЕСИА) для расшифровки токена auth_jwt $arg_code; # задаём токен auth_jwt_grant_set $oid urn:esia:sbj urn:esia:sbj:oid; # извлекаем oid из расшифрованного тела токена try_files /try?username=$oid; # перенаправляем на дальнейшую обработку } location =/try { internal; if ($arg_username = "") { return 401 UNAUTHORIZED; } # если oid не получен, то значит пользователь не авторизован encrypted_session_expires 43200; # задаём время жизни сессии 12 часов (12 * 60 * 60 = 43200) set_secure_random_alphanum $password 8; # задаём случайный пароль для basic авторизации set $username_password ESIA-$arg_username:$password; # задаём basic авторизацию set_encode_base64 $username_password_encode $username_password; # кодируем basic авторизацию set_encrypt_session $auth_encrypt $username_password_encode; # зашифровываем basic авторизацию set_encode_base64 $auth_encode $auth_encrypt; # кодируем зашифрованную basic авторизацию add_header Set-Cookie "Auth=$auth_encode; Max-Age=43200"; # помещаем зашифрованную basic авторизацию в авторизационную куку на 12 часов (12 * 60 * 60 = 43200) return 303 /; # перенаправляем в начало } |
На этом все. Теперь вы знаете как сделать авторизацию через ЕСИА.