mirror of
https://github.com/lkddi/Xboard.git
synced 2026-04-14 19:40:53 +08:00
eat: add reCAPTCHA v3 and Cloudflare Turnstile verification support
- Implement reCAPTCHA v3 with score-based validation - Add Cloudflare Turnstile as captcha alternative - Create reusable CaptchaService for unified validation - Support switching between recaptcha, recaptcha-v3, and turnstile - Maintain backward compatibility with existing configurations
This commit is contained in:
@@ -18,11 +18,17 @@ class CommController extends Controller
|
||||
'email_whitelist_suffix' => (int) admin_setting('email_whitelist_enable', 0)
|
||||
? Helper::getEmailSuffix()
|
||||
: 0,
|
||||
'is_recaptcha' => (int) admin_setting('recaptcha_enable', 0) ? 1 : 0,
|
||||
'is_captcha' => (int) admin_setting('captcha_enable', 0) ? 1 : 0,
|
||||
'captcha_type' => admin_setting('captcha_type', 'recaptcha'),
|
||||
'recaptcha_site_key' => admin_setting('recaptcha_site_key'),
|
||||
'recaptcha_v3_site_key' => admin_setting('recaptcha_v3_site_key'),
|
||||
'recaptcha_v3_score_threshold' => admin_setting('recaptcha_v3_score_threshold', 0.5),
|
||||
'turnstile_site_key' => admin_setting('turnstile_site_key'),
|
||||
'app_description' => admin_setting('app_description'),
|
||||
'app_url' => admin_setting('app_url'),
|
||||
'logo' => admin_setting('logo'),
|
||||
// 保持向后兼容
|
||||
'is_recaptcha' => (int) admin_setting('captcha_enable', 0) ? 1 : 0,
|
||||
];
|
||||
return $this->success($data);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class AuthController extends Controller
|
||||
]);
|
||||
|
||||
[$success, $result] = $this->mailLinkService->handleMailLink(
|
||||
$params['email'],
|
||||
$params['email'],
|
||||
$request->input('redirect')
|
||||
);
|
||||
|
||||
@@ -92,39 +92,39 @@ class AuthController extends Controller
|
||||
// 处理直接通过token重定向
|
||||
if ($token = $request->input('token')) {
|
||||
$redirect = '/#/login?verify=' . $token . '&redirect=' . ($request->input('redirect', 'dashboard'));
|
||||
|
||||
|
||||
return redirect()->to(
|
||||
admin_setting('app_url')
|
||||
? admin_setting('app_url') . $redirect
|
||||
: url($redirect)
|
||||
? admin_setting('app_url') . $redirect
|
||||
: url($redirect)
|
||||
);
|
||||
}
|
||||
|
||||
// 处理通过验证码登录
|
||||
if ($verify = $request->input('verify')) {
|
||||
$userId = $this->mailLinkService->handleTokenLogin($verify);
|
||||
|
||||
|
||||
if (!$userId) {
|
||||
return response()->json([
|
||||
'message' => __('Token error')
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
||||
$user = \App\Models\User::find($userId);
|
||||
|
||||
|
||||
if (!$user) {
|
||||
return response()->json([
|
||||
'message' => __('User not found')
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
||||
$authService = new AuthService($user);
|
||||
|
||||
|
||||
return response()->json([
|
||||
'data' => $authService->generateAuthData()
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Invalid request')
|
||||
], 400);
|
||||
@@ -136,7 +136,7 @@ class AuthController extends Controller
|
||||
public function getQuickLoginUrl(Request $request)
|
||||
{
|
||||
$authorization = $request->input('auth_data') ?? $request->header('authorization');
|
||||
|
||||
|
||||
if (!$authorization) {
|
||||
return response()->json([
|
||||
'message' => ResponseEnum::CLIENT_HTTP_UNAUTHORIZED
|
||||
@@ -144,14 +144,14 @@ class AuthController extends Controller
|
||||
}
|
||||
|
||||
$user = AuthService::findUserByBearerToken($authorization);
|
||||
|
||||
|
||||
if (!$user) {
|
||||
return response()->json([
|
||||
'message' => ResponseEnum::CLIENT_HTTP_UNAUTHORIZED_EXPIRED
|
||||
], 401);
|
||||
}
|
||||
|
||||
$url = $this->mailLinkService->getQuickLoginUrl($user, $request->input('redirect'));
|
||||
|
||||
$url = $this->loginService->generateQuickLoginUrl($user, $request->input('redirect'));
|
||||
return $this->success($url);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,23 +7,22 @@ use App\Http\Requests\Passport\CommSendEmailVerify;
|
||||
use App\Jobs\SendEmailJob;
|
||||
use App\Models\InviteCode;
|
||||
use App\Models\User;
|
||||
use App\Services\CaptchaService;
|
||||
use App\Utils\CacheKey;
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use ReCaptcha\ReCaptcha;
|
||||
|
||||
class CommController extends Controller
|
||||
{
|
||||
|
||||
public function sendEmailVerify(CommSendEmailVerify $request)
|
||||
{
|
||||
if ((int) admin_setting('recaptcha_enable', 0)) {
|
||||
$recaptcha = new ReCaptcha(admin_setting('recaptcha_key'));
|
||||
$recaptchaResp = $recaptcha->verify($request->input('recaptcha_data'));
|
||||
if (!$recaptchaResp->isSuccess()) {
|
||||
return $this->fail([400, __('Invalid code is incorrect')]);
|
||||
}
|
||||
// 验证人机验证码
|
||||
$captchaService = app(CaptchaService::class);
|
||||
[$captchaValid, $captchaError] = $captchaService->verify($request);
|
||||
if (!$captchaValid) {
|
||||
return $this->fail($captchaError);
|
||||
}
|
||||
|
||||
$email = $request->input('email');
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\Models\Order;
|
||||
use App\Models\Plan;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\User;
|
||||
use App\Services\Auth\LoginService;
|
||||
use App\Services\AuthService;
|
||||
use App\Services\UserService;
|
||||
use App\Utils\CacheKey;
|
||||
@@ -19,6 +20,14 @@ use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
protected $loginService;
|
||||
|
||||
public function __construct(
|
||||
LoginService $loginService
|
||||
) {
|
||||
$this->loginService = $loginService;
|
||||
}
|
||||
|
||||
public function getActiveSession(Request $request)
|
||||
{
|
||||
$user = User::find($request->user()->id);
|
||||
@@ -205,15 +214,7 @@ class UserController extends Controller
|
||||
return $this->fail([400, __('The user does not exist')]);
|
||||
}
|
||||
|
||||
$code = Helper::guid();
|
||||
$key = CacheKey::get('TEMP_TOKEN', $code);
|
||||
Cache::put($key, $user->id, 60);
|
||||
$redirect = '/#/login?verify=' . $code . '&redirect=' . ($request->input('redirect') ? $request->input('redirect') : 'dashboard');
|
||||
if (admin_setting('app_url')) {
|
||||
$url = admin_setting('app_url') . $redirect;
|
||||
} else {
|
||||
$url = url($redirect);
|
||||
}
|
||||
$url = $this->loginService->generateQuickLoginUrl($user, $request->input('redirect'));
|
||||
return $this->success($url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,15 +85,15 @@ class ConfigController extends Controller
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$key = $request->input('key');
|
||||
|
||||
|
||||
// 构建配置数据映射
|
||||
$configMappings = $this->getConfigMappings();
|
||||
|
||||
|
||||
// 如果请求特定分组,直接返回
|
||||
if ($key && isset($configMappings[$key])) {
|
||||
return $this->success([$key => $configMappings[$key]]);
|
||||
}
|
||||
|
||||
|
||||
return $this->success($configMappings);
|
||||
}
|
||||
|
||||
@@ -190,15 +190,23 @@ class ConfigController extends Controller
|
||||
'email_whitelist_enable' => (bool) admin_setting('email_whitelist_enable', 0),
|
||||
'email_whitelist_suffix' => admin_setting('email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT),
|
||||
'email_gmail_limit_enable' => (bool) admin_setting('email_gmail_limit_enable', 0),
|
||||
'recaptcha_enable' => (bool) admin_setting('recaptcha_enable', 0),
|
||||
'captcha_enable' => (bool) admin_setting('captcha_enable', 0),
|
||||
'captcha_type' => admin_setting('captcha_type', 'recaptcha'),
|
||||
'recaptcha_key' => admin_setting('recaptcha_key', ''),
|
||||
'recaptcha_site_key' => admin_setting('recaptcha_site_key', ''),
|
||||
'recaptcha_v3_secret_key' => admin_setting('recaptcha_v3_secret_key', ''),
|
||||
'recaptcha_v3_site_key' => admin_setting('recaptcha_v3_site_key', ''),
|
||||
'recaptcha_v3_score_threshold' => admin_setting('recaptcha_v3_score_threshold', 0.5),
|
||||
'turnstile_secret_key' => admin_setting('turnstile_secret_key', ''),
|
||||
'turnstile_site_key' => admin_setting('turnstile_site_key', ''),
|
||||
'register_limit_by_ip_enable' => (bool) admin_setting('register_limit_by_ip_enable', 0),
|
||||
'register_limit_count' => admin_setting('register_limit_count', 3),
|
||||
'register_limit_expire' => admin_setting('register_limit_expire', 60),
|
||||
'password_limit_enable' => (bool) admin_setting('password_limit_enable', 1),
|
||||
'password_limit_count' => admin_setting('password_limit_count', 5),
|
||||
'password_limit_expire' => admin_setting('password_limit_expire', 60)
|
||||
'password_limit_expire' => admin_setting('password_limit_expire', 60),
|
||||
// 保持向后兼容
|
||||
'recaptcha_enable' => (bool) admin_setting('captcha_enable', 0)
|
||||
],
|
||||
'subscribe_template' => [
|
||||
'subscribe_template_singbox' => $this->formatTemplateContent(
|
||||
@@ -225,7 +233,7 @@ class ConfigController extends Controller
|
||||
}
|
||||
admin_setting([$k => $v]);
|
||||
}
|
||||
|
||||
|
||||
return $this->success(true);
|
||||
}
|
||||
|
||||
@@ -240,23 +248,23 @@ class ConfigController extends Controller
|
||||
{
|
||||
return match ($format) {
|
||||
'json' => match (true) {
|
||||
is_array($content) => json_encode(
|
||||
value: $content,
|
||||
flags: JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||||
),
|
||||
|
||||
is_string($content) && str($content)->isJson() => rescue(
|
||||
callback: fn() => json_encode(
|
||||
value: json_decode($content, associative: true, flags: JSON_THROW_ON_ERROR),
|
||||
is_array($content) => json_encode(
|
||||
value: $content,
|
||||
flags: JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||||
),
|
||||
rescue: $content,
|
||||
report: false
|
||||
),
|
||||
|
||||
default => str($content)->toString()
|
||||
},
|
||||
|
||||
|
||||
is_string($content) && str($content)->isJson() => rescue(
|
||||
callback: fn() => json_encode(
|
||||
value: json_decode($content, associative: true, flags: JSON_THROW_ON_ERROR),
|
||||
flags: JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||||
),
|
||||
rescue: $content,
|
||||
report: false
|
||||
),
|
||||
|
||||
default => str($content)->toString()
|
||||
},
|
||||
|
||||
default => str($content)->toString()
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user