- PVSM.RU - https://www.pvsm.ru -

Рецепты Nginx: авторизация через ЕСИА

Для приготовления авторизации через ЕСИА нам понадобится сам nginx [1] и его плагины encrypted-session [2], headers-more [3], auth_request [4], uuid4 [5], set-misc [6], sign [7], jwt [8]. (Я дал ссылки на свои форки, т.к. делал некоторые изменения, которые пока не удалось пропихнуть в оригинальные репозитории. Можно также воспользоваться готовым образом [9].)

Для начала зададим

encrypted_session_key "abcdefghijklmnopqrstuvwxyz123456";

(это необходимое условие работы плагина encrypted-session [2]).

Дальше, на всякий случай, отключаем авторизационный заголовок

more_clear_input_headers Authorization;

Теперь защищаем всё авторизацией

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; # пользователь авторизован
}

Для авторизованных пользователей показываем контент из их папки

location / {
    alias html/$remote_user/;
}

А при отсутствии авторизации перенаправляем на ЕСИА

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&timestamp=$timestamp_escape; # перенаправляем на ЕСИА

После успешной авторизации пользователя в ЕСИА, его перенаправляет на адрес возврата

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 /; # перенаправляем в начало
}

Автор: RekGRpth

Источник [10]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/nginx/321164

Ссылки в тексте:

[1] nginx: https://github.com/RekGRpth/nginx

[2] encrypted-session: https://github.com/RekGRpth/encrypted-session-nginx-module

[3] headers-more: https://github.com/RekGRpth/headers-more-nginx-module

[4] auth_request: https://nginx.org/ru/docs/http/ngx_http_auth_request_module.html

[5] uuid4: https://github.com/RekGRpth/nginx-uuid4-module

[6] set-misc: https://github.com/RekGRpth/set-misc-nginx-module

[7] sign: https://github.com/RekGRpth/ngx_http_sign_module

[8] jwt: https://github.com/RekGRpth/nginx-jwt-module

[9] готовым образом: https://hub.docker.com/r/rekgrpth/nginx

[10] Источник: https://habr.com/ru/post/456538/?utm_campaign=456538&utm_source=habrahabr&utm_medium=rss