在 symfony 6.4 中应使用 session 存储 + 自定义 validator 约束实现验证码,生成 4 位无歧义字符并转小写存入 session,twig 纯 css 渲染混淆,验证通过后立即清除 session 值以确保一次性使用。

在 Symfony 6.4 中创建验证码用于登录、注册或表单提交等场景,需避开已废弃的第三方 bundle(如 Gregwar/CaptchaBundle),改用轻量可控的方案:基于 Symfony 的 Validator + 自定义约束 + Twig 渲染 + Session 存储校验值,不依赖外部字体或 GD 扩展强制开启。
生成纯文本验证码并存入 Session
第一步:在控制器中生成 4 位随机字母数字组合,排除易混淆字符(0/O/l/1/I):
```php
$chars = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789';
$code = '';
for ($i = 0; $i $code .= $chars[random_int(0, strlen($chars) - 1)];
}
$this->get('session')->set('captcha_code', strtolower($code));
```
第二步:将 $code 传入模板,用 CSS 随机旋转、变色、加虚线干扰——无需 GD 或 imagettftext,纯前端混淆即可防基础 OCR;【必须调用 strtolower() 后存入 Session,否则大小写比对必然失败】
第三步:在 Twig 模板中渲染为可读但难自动识别的文本块:
```twig
```
创建自定义验证码验证约束
方法一:定义约束类 App\Validator\CaptchaCode
在 src/Validator/ 目录下新建 CaptchaCode.php:
```php
namespace App\Validator;
use Attribute;
use Symfony\Component\Validator\Constraint;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)]
class CaptchaCode extends Constraint
{
public string $message = 'The verification code is incorrect.';
}
```
方法二:实现验证器 App\Validator\CaptchaCodeValidator
在同目录下新建 CaptchaCodeValidator.php:
```php
namespace App\Validator;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
class CaptchaCodeValidator extends ConstraintValidator
{
public function __construct(private SessionInterface $session) { }
public function validate(mixed $value, Constraint $constraint): void
{
if (!$constraint instanceof CaptchaCode) {
throw new UnexpectedTypeException($constraint, CaptchaCode::class);
}
if (null === $value || '' === $value) {
return;
}
$expected = $this->session->get('captcha_code');
if (!$expected || strtolower((string) $value) !== $expected) {
$this->context->buildViolation($constraint->message)->addViolation();
} else {
$this->session->remove('captcha_code'); // 一次性使用,验证后立即清除
}
}
}
```
注意:Session 移除必须放在验证通过分支内,否则同一验证码可重复提交多次。
在表单类中绑定验证码字段与约束
第一步:确保表单类位于 src/Form/ 目录,命名以 Type 结尾(如 LoginType.php)
第二步:在对应实体或 DTO 中添加 captchaCode 属性,并标注约束:
```php
namespace App\Form;
use App\Validator\CaptchaCode;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
class LoginType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('captchaCode', TextType::class, [
'label' => 'Verification code',
'attr' => ['autocomplete' => 'off', 'maxlength' => 4],
]);
}
}
```
第三步:在控制器中使用该表单,并确保 handleRequest 后触发验证:
```php
$form = $this->createForm(LoginType::class, $loginDto);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// 验证通过,执行登录逻辑
}
```
第四步:在模板中同时渲染验证码显示区与输入框:
```twig
{{ form_row(form.captchaCode) }}
```











