mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-15 21:41:03 +08:00
feat: Refine captcha configuration and drivers
Introduce a configurable captcha manager with drivers for image, Cloudflare Turnstile, and Google reCAPTCHA, including fallback behaviour. Refactor login, signup, complain, and related flows to use the new abstraction while simplifying the legacy image endpoint. Document captcha environment options and restore classic defaults in .env.example. Signed-off-by: Qi HU <github@spcsky.com>
This commit is contained in:
120
app/Services/Captcha/CaptchaManager.php
Normal file
120
app/Services/Captcha/CaptchaManager.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Captcha;
|
||||
|
||||
use App\Services\Captcha\Exceptions\CaptchaValidationException;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class CaptchaManager
|
||||
{
|
||||
/** @var array<string, CaptchaDriverInterface> */
|
||||
protected array $drivers = [];
|
||||
|
||||
protected ?array $config = null;
|
||||
|
||||
public function driver(?string $name = null): CaptchaDriverInterface
|
||||
{
|
||||
$name = $name ?? $this->getDefaultDriver();
|
||||
|
||||
$driver = $this->getDriverInstance($name);
|
||||
|
||||
if ($name !== 'image' && !$driver->isEnabled()) {
|
||||
return $this->driver('image');
|
||||
}
|
||||
|
||||
return $driver;
|
||||
}
|
||||
|
||||
public function render(array $context = []): string
|
||||
{
|
||||
return $this->driver()->render($context);
|
||||
}
|
||||
|
||||
public function verify(array $payload, array $context = []): bool
|
||||
{
|
||||
try {
|
||||
return $this->driver()->verify($payload, $context);
|
||||
} catch (CaptchaValidationException $exception) {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->driver()->isEnabled();
|
||||
}
|
||||
|
||||
protected function getDriverInstance(string $name): CaptchaDriverInterface
|
||||
{
|
||||
if (!isset($this->drivers[$name])) {
|
||||
try {
|
||||
$this->drivers[$name] = $this->resolveDriver($name);
|
||||
} catch (\InvalidArgumentException $exception) {
|
||||
if ($name !== 'image') {
|
||||
return $this->getDriverInstance('image');
|
||||
}
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->drivers[$name];
|
||||
}
|
||||
|
||||
protected function resolveDriver(string $name): CaptchaDriverInterface
|
||||
{
|
||||
$config = $this->getConfigValue("drivers.$name", []);
|
||||
|
||||
if (!is_array($config) || empty($config)) {
|
||||
throw new \InvalidArgumentException("Captcha driver [$name] is not defined.");
|
||||
}
|
||||
|
||||
$driverClass = Arr::get($config, 'class');
|
||||
|
||||
if (!$driverClass || !class_exists($driverClass)) {
|
||||
throw new \InvalidArgumentException("Captcha driver class for [$name] is invalid.");
|
||||
}
|
||||
|
||||
$driver = new $driverClass($config);
|
||||
|
||||
if (!$driver instanceof CaptchaDriverInterface) {
|
||||
throw new \InvalidArgumentException("Captcha driver [$name] must implement " . CaptchaDriverInterface::class);
|
||||
}
|
||||
|
||||
return $driver;
|
||||
}
|
||||
|
||||
protected function getDefaultDriver(): string
|
||||
{
|
||||
return (string) $this->getConfigValue('default', 'image');
|
||||
}
|
||||
|
||||
protected function getConfigValue(string $key, $default = null)
|
||||
{
|
||||
if ($this->config === null) {
|
||||
$config = null;
|
||||
if (function_exists('app')) {
|
||||
try {
|
||||
$repository = app('config');
|
||||
if ($repository) {
|
||||
$config = $repository->get('captcha');
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$config = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_array($config) && function_exists('nexus_config')) {
|
||||
$config = nexus_config('captcha', []);
|
||||
}
|
||||
|
||||
if (!is_array($config)) {
|
||||
$path = (defined('ROOT_PATH') ? ROOT_PATH : dirname(__DIR__, 3) . DIRECTORY_SEPARATOR) . 'config/captcha.php';
|
||||
$config = is_file($path) ? require $path : [];
|
||||
}
|
||||
|
||||
$this->config = is_array($config) ? $config : [];
|
||||
}
|
||||
|
||||
return Arr::get($this->config, $key, $default);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user