Один код, любое развёртывание. Приложению не важно, где работает Veriqa — в облаке Veriqa,
в вашем контейнере Docker или службой (systemd либо служба Windows) на вашей машине. Варианты
различаются только адресом issuer’а и тем, где заведён клиент; код приложения ниже одинаков
для всех, а переключение сводится к одному значению
issuer-uri.1. Подключите стартеры
Основной путь для Java — Spring Security OAuth2 Client через стартер Spring Boot. Версию задавать не нужно: её берёт на себя BOM Spring Boot. Вместе с ним идёт второй стартер: OAuth2-стартер объявляетspring-boot-starter, Spring Security и клиента OAuth2/OIDC — и никакого веб-сервера,
так что сам по себе он даёт приложение, которое стартует и завершается, ни разу не обслужив callback:
2. Заведите клиента на стороне Veriqa
Veriqa Cloud сейчас недоступен — строки про облако описывают контракт его API. Используйте
self-hosted; подробности — в Veriqa Cloud.
У self-hosted две поставки, и для этой страницы они равнозначны. Сервер работает в контейнере
Docker — быстрый старт self-hosted — либо ставится из архива юнитом
systemd или службой Windows, без Docker и без рантайма .NET на машине —
установка службой ОС. Выбор определяет способ поставки сервера, а не
регистрацию клиента, адрес issuer’а и код ниже.
Секрет не обязателен. Минимальный рабочий набор —
issuer, client_id, redirect_uri:
public-клиент с PKCE, и это дефолт облака. Confidential-клиент нужен, только если вы хотите
аутентифицировать серверное приложение секретом; в облаке секрет выпускается отдельным явным
действием на экране Applications и показывается один раз.
3. Опишите регистрацию клиента
issuer-uri включает discovery: Spring сам читает /.well-known/openid-configuration и находит
остальные эндпоинты.
PKCE включать отдельно не нужно. Spring Security применяет его автоматически, когда
client-authentication-method равен none; никакой дополнительной настройки для public-клиента
не требуется. Секрет при этом не задаётся вовсе — не пустой строкой, а отсутствием ключа.issuer-uri — это адрес, который дал шаг 2: замените им
https://auth.your-domain.com, а client-id — идентификатором заведённого там клиента. Spring
сверяет discovery-документ с этим значением на старте, поэтому забытый плейсхолдер валит запуск, а не
первый вход.
Секреты держите в окружении (${VERIQA_CLIENT_SECRET}), а не в закоммиченном application.yml.
${…} Spring разрешает из окружения процесса, поэтому confidential-варианту нужна переменная,
экспортированная в той оболочке, из которой запускается приложение:
client-authentication-method: none ключа в
application.yml нет — именно нет, а не пустой. Не задайте переменную для confidential-варианта —
запуск упадёт на неразрешённом плейсхолдере.
Переключение между вариантами — облако, Docker, служба ОС — правка одного issuer-uri.
4. Включите вход
Минимальной конфигурации достаточно:oauth2Login() поднимает весь поток — редирект на страницу
входа Veriqa, обработку callback и создание сессии.
SecurityConfig.java
redirect_uri.
5. Прочитайте claims
Аутентифицированный пользователь доступен какOidcUser:
ProfileController.java
anyRequest().authenticated(), поэтому первое обращение начинает вход, а ответ после него
показывает, что вход дал.
Базовый набор Veriqa кладёт в токены сама:
Claims канала выдаются только по scope
channel:
Без запрошенного scope
channel эти два claim не попадают ни в один токен — и, следовательно,
не появляются в ответе userinfo, который зеркалит access_token. Именно по ним приложение различает
привязанные каналы, поэтому для сценария привязки аккаунта scope обязателен.
amr приходит в id_token массивом строк — так его определяет OIDC Core 1.0 §2, и массив
там даже при единственном методе аутентификации. Читайте его из ID-токена и берите первый
элемент:/connect/userinfo, который Spring
вызывает штатно при запрошенном profile (как в конфигурации выше) и объединяет с claims
id_token. Но в userinfo значение — строка, а не массив, поэтому user.getClaimAsString("amr")
на объединённом наборе зависит от того, чей claim победил в слиянии; чтение из getIdToken()
такой развилки не имеет.Для привязки канала к аккаунту этого всё равно недостаточно: amr называет тип канала, но не
идентификатор пользователя в нём. Идентификатор даёт channel_user_id под scope channel.6. Ограничьте вход конкретным каналом
Стандартный OIDC-параметрacr_values формата channel:{тип} сужает выбор на странице входа. В
Spring Security он добавляется кастомайзером authorization-запроса:
SecurityConfig.java
SecurityConfig.java
channel:telegram channel:whatsapp) — пользователь выбирает из
перечисленных. Без параметра доступны все включённые на сервере каналы.
7. Контрольная точка
Запустите приложение из каталога проекта, в той оболочке, где шаг 3 экспортировал секрет (только для confidential-варианта):http://127.0.0.1:8080 — том адресе, из которого собран redirect_uri,
зарегистрированный в шаге 2.
1
Проверьте discovery
curl https://auth.your-domain.com/.well-known/openid-configuration — с вашим issuer-uri
вместо хоста — возвращает метаданные с https-URL.2
Запустите вход
Откройте
http://127.0.0.1:8080/ — маршрут закрыт anyRequest().authenticated(), поэтому Spring
отправит браузер на страницу Veriqa с QR и каналами.3
Подтвердите на телефоне
Подтвердите запрос в доверенном канале; браузер вернётся на
http://127.0.0.1:8080/login/oauth2/code/veriqa, а Spring перенаправит его обратно на /.4
Проверьте claims
/ отвечает приветствием из шага 5: OidcUser несёт sub, а при
запрошенном scope channel на нём доступен и channel_type.Дальше
Сценарии интеграции
Привязка канала, повторное подтверждение и подтверждение действия — на уровне HTTP.
Быстрый старт: self-hosted
Развернуть свой issuer в Docker.
Установка службой ОС
Тот же issuer без Docker — systemd или служба Windows, из архива.
OIDC + Veriqa: разбор
Где Veriqa встаёт в стандартный поток.
Hardening к продакшну
Что проверить перед выпуском.