Аутентификация в политиках и сценариях
Привязка профиля аутентификации закрывает пути: целиком, все кроме перечисленных или только перечисленные. Если правило зависит от чего-то ещё — метода запроса, заголовка, адреса клиента или от того, кто вошёл, — используйте политики и сценарии.
Что можно сделать
- Потребовать вход по условию — действие Аутентификация в политике или вызов
authenticate()в сценарии. - Проверить, кто вошёл — условие Аутентификация в политике или
identity()в сценарии. - Передать приложению сведения о пользователе в своём заголовке — в сценарии.
Порядок проверки
Сначала срабатывают привязки профилей к сервису, затем политики и сценарии. Политика может ужесточить требование привязки, но не отменить его: путь, закрытый привязкой, политикой не открыть.
Условия Аутентификация сами вход не требуют. Они видят только пользователя, которого уже узнала привязка или действие Аутентификация, выполненное раньше. Если клиент не входил, условие ложно, а с отметкой НЕ — истинно.
Политики
Действие «Аутентификация»
Действие — Аутентификация, Атрибут — Профилем, Параметры — нужный профиль. Действие доступно в месте помещения Обработка запроса на пути к серверу.
Клиент, который ещё не вошёл, получает требование входа этого профиля: окно браузера, форму входа или ответ 401 — в зависимости от модулей приёма профиля.
Пример: вход только на разделе /basic.
| Группа | Атрибут | Значение | |
|---|---|---|---|
| ЕСЛИ | HTTP URI | Сегмент пути = | /basic |
| ТО | Аутентификация | Профилем | BASIC AUTH |
Условие «Аутентификация»
| Атрибут | Истинно, когда |
|---|---|
| Пользователь | имя пользователя равно значению |
| Группа | пользователь состоит в группе |
| Атрибут | атрибут пользователя с указанным именем равен значению |
Если на запросе сработали несколько профилей, группы и атрибуты объединяются, а имя пользователя берётся у последнего сработавшего профиля.
Пример: раздел /admin только для группы admin.
| НЕ | Группа | Атрибут | Значение | |
|---|---|---|---|---|
| ЕСЛИ | ✔ | Аутентификация | Группа = | admin |
| И | HTTP URI | Сегмент пути = | /admin | |
| ТО | Кастомная страница | Простой HTML | страница «Нет доступа» |
Раздел /admin должен быть закрыт привязкой профиля к сервису. Иначе клиент, который ещё не вошёл, сразу получит страницу «Нет доступа» вместо предложения войти.
Сценарии
Потребовать вход
authenticate("Имя профиля", { параметры })Профиль указывают по имени или по UUID. Ссылку на него добавьте в раздел Связанные сущности с типом Профиль аутентификации: без неё вызов завершится ошибкой. UUID надёжнее имени — переименование профиля ломает вызовы, которые ссылались на него по имени.
Все параметры необязательны. Пути и группы можно задать строкой или списком.
| Параметр | Что делает |
|---|---|
only | требовать вход только на этих путях |
except | требовать вход везде, кроме этих путей |
groups | пускать только пользователей хотя бы из одной группы |
on_deny | ответ при отказе по группам: { status = 403 }, { redirect = "/denied" } или { body = "<h1>Нет доступа</h1>" } |
app_logout_paths | адреса выхода приложения |
only и except вместе указать нельзя. Если не задан ни один из них, вход требуется на каждом запросе, который дошёл до вызова. Неизвестный параметр — ошибка сценария: опечатка вроде group вместо groups не пропустит молча всех.
Узнать, кто вошёл
local auth = require("auth")
local me = auth.identity() -- nil или { user = "...", groups = { ... }, attrs = { ... } }
if auth.in_group(me, "admins") then
-- ...
endПример: разные клиенты — разные профили
Интеграции приходят с токеном от IdP, люди и скрипты — с логином и паролем. Читать может любой вошедший, изменять — только администраторы. /api/health открыт для мониторинга.
local method = ngx.req.get_method()
local writes = method ~= "GET" and method ~= "HEAD"
local authorization = ngx.var.http_authorization or ""
if authorization:find("^Bearer ") then
authenticate("JWT BACKEND TEST", {
except = "/api/health",
groups = writes and { "admins" } or nil, -- группа из токена IdP
})
else
authenticate("BASIC AUTH", {
except = "/api/health",
groups = writes and { "admin" } or nil, -- группа из набора пользователей
})
end
-- Приложению не нужно разбирать токен: кто пришёл, видно в отдельном заголовке.
local me = require("auth").identity()
if me then
set_req_header("X-Caller", me.user)
else
-- На /api/health входа нет: не даём клиенту подставить X-Caller самому.
ngx.req.clear_header("X-Caller")
end