Cookie авторизация в Nginx

January 17, 2019

Закрываем test версию сайта от посторонних глаз

Типичная задача: есть тестовая версия проекта с публичным доменом. Нужно как-то закрыть эту версию. Раньше пользовался банально базовой авторизацией, реализованной через Nginx, до тех пор пока не столкнулся с проблемами использования.

Проблема 1. Работа с RESTfull API: если вы правильно отдаете все коды HTTP ответов, то вы должны выдавать 401 для неавторизованных пользователей. И тут я столкнулся с конфликтами HTTP ответов, так как если приложение выдает 401, то при использовании базовой авторизации начинают вылезать авторизационные окна, хотя вы уже залогинились.

Проблема 2. Она точно такая же как и первая, и опять же про конфликты HTTP ответов. Если вы используете сторонние standalone сервисы, а эти сервисы, в свою очередь, реализует авторизацию на стороне приложения используя механизмы Basic Authorization, то опять получаем конфликты.

В итоге перешел на авторизацию через cookie средствами Nginx. Причем если зайти без авторизации то в ответ будет либо 404, либо будет редирект на основной production домен (смотря что вам нужно).

К примеру, основной домен GeekJOB.ru, тогда для тестов есть домены geekjob.pro и geekjob.org. Но чтобы различные поисковики воспринимали эти домены как зеркала, по дефолту делаем редирект на основной домен. А чтобы зайти на эти домены и увидеть ресурс, нужно выставит нужную куку.

Cookie авторизация на стороне Nginx

server {
...
location / {
if ($cookie_access != "secretkey") {
return 404;
}
}
...
}

или

server {
server_name geekjob.pro;
...
location /
{
if ($cookie_access != "secretkey") {
return 302 https://geekjob.ru$request_uri;
}
...
}
...
}

Таким образом, если не выставлена нужная кука, то посторонний или поисковый бот уйдут на основной ресурс. Самый простой способ через консоль разработчика выполнить:

document.cookie = 'access=secretkey'

User friendly авторизация

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

server {
server_name geekjob.pro;
...
location /
{
if
($arg_access) {
add_header "Set-Cookie" "access=$arg_access";
return 302 /;
}
if ($cookie_access != "secretkey") {
return 302 https://geekjob.ru$request_uri;
}
...
}
...
}

Мы проверяем есть ли аргумент access в запросе и если есть, то выставляем куку со значением, которое пришло в запросе, после чего делаем редирект на главную без аргументов (поэтому этот блок будет проигнорирован). Проверяем куку и если secretkey совпадают, то обрабатываем дальше запросы иначе просто возвращаем 404 или редиректим (зависит от того, что вам нужно).

Теперь для авторизации нужно передать URL с параметром:

https://your.domain?access=secretkey

После чего вы получаете доступ к сайту, который нужно скрыть от посторонних глаз. Такой вот лайфхак.



Profile picture

Written by Alexander Mayorov
Full Stack CTO