В версии 8.2 появятся несколько важных нововведений: встроенный режим sudo с атрибутами IS_AUTHENTICATED_RECENTLY и IS_AUTHENTICATED_VERY_RECENTLY, которые требуют повторной аутентификации перед выполнением конфиденциальных действий, опция --concurrency для параллельной обработки сообщений в Messenger, ускоряющая работу до 7,5 раза, параметр prefetch_count для AMQP и поддержка PGP/MIME в компоненте Mime, позволяющая подписывать и шифровать письма с помощью ключей OpenPGP.
Релиз запланирован на ноябрь 2026 года.
Встроенный режим sudo
Встроенный режим sudo позволяет приложениям требовать повторный вход в систему перед выполнением важных действий, например изменения адреса электронной почты или удаления учетной записи.
Флаг IS_AUTHENTICATED_FULLY — самая строгая проверка статуса авторизации в Symfony, однако указывает она лишь на то, как была запущена сессия. Поэтому, скажем, пользователь, вошедший в систему восемь часов назад и оставивший ноутбук разблокированным, по-прежнему считается полностью аутентифицированным. В теории любой может совершить оплату с его аккаунта или удалить учетную запись. Сервисы вроде GitHub решают эту проблему с помощью режима sudo, запрашивающего учетные данные заново перед выполнением потенциально опасных действий. В Symfony 8.2 эта функция будет добавлена на уровне ядра.
Появятся два атрибута безопасности, расширяющих возможности IS_AUTHENTICATED_FULLY: IS_AUTHENTICATED_RECENTLY (учетные данные введены в течение последних двух часов) и IS_AUTHENTICATED_VERY_RECENTLY (в течение последних пяти минут). Их можно применять везде, где применяются другие атрибуты серии IS_AUTHENTICATED_*, включая access_control и шаблоны Twig.
Например, для изменения адреса электронной почты можно установить требование о недавнем входе в систему, а для удаления учетной записи — о входе, совершенном совсем недавно:
// src/Controller/AccountController.php
use Symfony\Component\Security\Http\Attribute\IsGranted;
// ...
#[IsGranted('IS_AUTHENTICATED_RECENTLY')]
public function changeEmail(): Response
{
// ...
}
#[IsGranted('IS_AUTHENTICATED_VERY_RECENTLY')]
public function deleteAccount(): Response
{
// ...
}
В security expressions также появятся функции is_recently_authenticated() и is_very_recently_authenticated(). Пользователи, авторизованные только через cookie «запомнить меня», не пройдут эти проверки, поскольку такой cookie может быть использован любым лицом, имеющим доступ к браузеру. Временные ограничения настраиваются в security.yaml в секундах:
# config/packages/security.yaml
security:
recent_authentication_lifetime: 3_600 # default: 7_200
very_recent_authentication_lifetime: 60 # default: 300
Если атрибуты отсутствуют, пользователи по умолчанию получают ошибку 403. Новый интерфейс ReAuthenticationEntryPointInterface позволяет перенаправить пользователей для повторной аутентификации вместо отображения ошибки. Для этого необходимо сначала создать сервис, реализующий новый интерфейс:
// src/Security/ConfirmPasswordEntryPoint.php
namespace App\Security;
use Symfony\Component\Security\Http\EntryPoint\ReAuthenticationEntryPointInterface;
// ...
final class ConfirmPasswordEntryPoint implements ReAuthenticationEntryPointInterface
{
public function __construct(
private UrlGeneratorInterface $urlGenerator,
) {
}
public function startReAuthentication(Request $request, TokenInterface $token): Response
{
// this page displays a password form that submits to the form_login check_path
return new RedirectResponse($this->urlGenerator->generate('app_confirm_password'));
}
}
Затем настроить брандмауэр для работы с ним с помощью нового параметра re_authentication_entry_point:
// config/packages/security.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use App\Security\ConfirmPasswordEntryPoint;
return App::config([
'security' => [
'firewalls' => [
'main' => [
'form_login' => [
// ...
],
're_authentication_entry_point' => ConfirmPasswordEntryPoint::class,
],
],
],
]);
Если точка входа брандмауэра уже реализует этот интерфейс, параметр можно пропустить. Новый механизм входа через OpenID Connect делает это автоматически: он перенаправляет пользователей обратно к провайдеру с параметром prompt=login, для повторного ввода учетных данных.
Symfony также использует свойство auth_time в ID-токене для проверки того, когда пользователь на самом деле прошел аутентификацию. Таким образом, автоматический вход через старую сессию у провайдера не считается новым входом в систему.
Ускорение рабочих процессов Messenger
Также будет ведена новая опция --concurrency для рабочих процессов Messenger. Она позволяет одному рабочему процессу параллельно обрабатывать несколько сообщений с помощью библиотеки amphp/parallel или расширения PHP parallel.
В тестах производительности с сообщениями, обработка каждого из которых занимает 20 мс, параметр --concurrency=8 показал производительность в 7,5 раз выше, чем у одного рабочего процесса.
Рабочий процесс по-прежнему самостоятельно извлекает сообщения, поэтому ему потребуется только одно соединение с транспортным протоколом, независимо от того, сколько сообщений обрабатывается параллельно. Исключение составляют пакетные обработчики: все сообщения в пакете должны обрабатываться одним и тем же дочерним процессом, поэтому параметр --concurrency не ускоряет их обработку, и для параллельной обработки пакетов следует продолжать запускать несколько рабочих процессов.
Транспортный протокол AMQP запрашивает у брокера по одному сообщению за раз, что требует одного цикла обмена данными по сети на каждое сообщение. RabbitMQ считает это наименее эффективным способом получения сообщений. Новый параметр prefetch_count регистрирует реального потребителя для каждой очереди и позволяет брокеру заранее отправлять ему сообщения.
В тестах по сравнению с локальным брокером скорость обработки сообщений была в 13–18 раз выше. Зарегистрированные потребители также отображаются в интерфейсе управления RabbitMQ. Значение prefetch_count должно быть больше размера извлечения рабочего процесса, который по умолчанию равен значению параметра --concurrency.
Предварительная загрузка по умолчанию отключена, поскольку она изменяет способ обработки сообщений. Теперь брокер определяет порядок между очередями, а любые предварительно загруженные сообщения, все еще ожидающие обработки, повторно доставляются при остановке рабочего процесса.
Отправка отложенных сообщений также станет менее затратной. В AMQP нет встроенных задержек, поэтому Symfony создает очередь задержки для каждого отдельного значения задержки. Стратегия повторных попыток по умолчанию добавляет колебания к этим задержкам, что приводит к появлению более тысячи различных значений, и при каждой повторной попытке обычно объявляется и привязывается новая очередь.
Задержки округляются в большую сторону (например, 5234 мс становится 5300 мс). Это на несколько порядков сокращает количество очередей задержек и гарантирует, что сообщения будут отправлены не раньше заданной задержки и не позднее, чем на 10% позже нее. Новый параметр delay[granularity] позволяет округлять задержки до фиксированного числа миллисекунд или отключить округление, установив его равным 1:
# .env
MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages?delay[granularity]=1000
Новое опциональное промежуточное ПО для ведения журналов фиксирует время обработки и объем используемой памяти для каждого сообщения. Его стоит включить на тех шинах, которые вы хотите отслеживать:
// config/packages/messenger.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
return App::config([
'framework' => [
'messenger' => [
'buses' => [
'messenger.bus.default' => [
'middleware' => ['logging'],
],
],
],
],
]);
Оно отслеживает все, что запускается после него в стеке, и записывает сообщения в канал мессенджера с контекстными ключами class, duration_ms и memory_usage (в байтах). Это позволяет создавать на их основе информационные панели и настраивать оповещения.
Вас также могут заинтересовать эти материалы
Электронные письма, подписанные и зашифрованные с помощью PGP/MIME
Symfony поддерживает подпись и шифрование электронных писем по стандарту S/MIME начиная с версии Symfony 4.4, а в Symfony 7.3 была добавлена возможность глобальной подписи и шифрования. Это позволяет настроить эту функцию один раз для всех писем. Однако S/MIME использует сертификаты X.509, выдаваемые центрами сертификации, в то время как многие пользователи вместо них используют ключи OpenPGP. В Symfony 8.2 будет добавлена поддержка этих ключей, а также улучшены существующие функции S/MIME.
В компонент Mime добавится поддержка PGP/MIME (RFC 3156). Она работает аналогично функции S/MIME: подписант добавляет к сообщению отдельную подпись, а шифровальщик шифрует его с помощью открытых ключей получателей:
use Symfony\Component\Mime\Crypto\PgpEncrypter;
use Symfony\Component\Mime\Crypto\PgpSigner;
$signer = new PgpSigner('/path/to/secret.asc', '/path/to/public.asc', $passphrase);
$signedEmail = $signer->sign($email);
$encrypter = new PgpEncrypter();
$encryptedEmail = $encrypter->encrypt($signedEmail, [
'alice@example.com' => '/path/to/alice.asc',
]);
В приложениях полного цикла это настраивается один раз в настройках Mailer:
# config/packages/mailer.yaml
framework:
mailer:
pgp_signer:
secret_key: '%kernel.project_dir%/config/keys/private.asc'
passphrase: '%env(PGP_PASSPHRASE)%'
pgp_encrypter:
keys:
'alice@example.com': '%kernel.project_dir%/config/keys/alice.asc'
# or use a service implementing PgpPublicKeyRepositoryInterface
# repository: App\Mailer\PublicKeyRepository
on_missing_key: 'fail' # fail | encrypt | skip
Затем в письма, которые нужно защитить, добавляются заголовки X-Pgp-Sign и/или X-Pgp-Encrypt. Symfony подписывает и шифрует их после отображения содержимого (поэтому это работает с TemplatedEmail) и всегда подписывает перед шифрованием:
$email->getHeaders()->addTextHeader('X-Pgp-Sign', 'true');
$email->getHeaders()->addTextHeader('X-Pgp-Encrypt', 'true');
Функция использует бинарный файл gpg через компонент Process, поэтому не требует никаких расширений PHP. Шифруется только тело сообщения, заголовки остаются видимыми. Функция находится в экспериментальной стадии, поэтому ее API может изменяться в незначительных версиях.
В ходе разработки поддержки PGP/MIME некоторые идеи были применены и к существующим функциям S/MIME. Ранее, если хотя бы у одного получателя не было сертификата S/MIME, сообщение отправлялось всем в незашифрованном виде. В Symfony 8.2 добавится параметр on_missing_certificate с теми же значениями, что и у PGP (fail, encrypt и skip). Сертификаты также можно указывать непосредственно в конфигурации:
# config/packages/mailer.yaml
framework:
mailer:
smime_encrypter:
certificates:
'alice@example.com': '%kernel.project_dir%/config/certificates/alice.crt'
on_missing_certificate: 'fail'
Для обеспечения обратной совместимости значением по умолчанию остается send_unencrypted, однако оно признано устаревшим, и в Symfony 9.0 в этом случае будет сгенерировано исключение. Поведение можно переопределить для каждого сообщения с помощью заголовка X-SMime-Encrypt (например, X-SMime-Encrypt: skip).