feat: Turnstile captcha, menu khách + nút tắt topbar cấu hình từ admin, ẩn setting nhạy cảm

- Turnstile (App\Support\Turnstile, middleware turnstile) cho login admin và login/register/forgot/reset của khách; cấu hình ở setting key=turnstile, secret mã hoá SignRSA.
- Menu sidebar khách (setting client_menu) và nút tắt topbar (setting client_quick_links) do admin sửa qua administrator/client-menu[/quick-links], khách đọc v1/setting/menu, v1/setting/quick-links.
- v1/setting và settings/public chỉ trả whitelist PublicSetting::FIELDS (trước đây lộ bot_token, inet_api_key).
- Cài đặt tài khoản khách (preferences), rate limit theo IP cho register/resend-verify.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
baodev0
2026-10-12 15:53:43 +07:00
co-authored by Claude Opus 5.5
parent 823af4a56a
commit e888a6ed5d
33 changed files with 1022 additions and 52 deletions
+9 -4
View File
@@ -31,13 +31,13 @@ Route::prefix('v1')
->as('client.')
->group(function () {
Route::controller(ClientController::class)->group(function () {
Route::post('login', 'login')->middleware('throttle:client-auth')->name('login');
Route::post('register', 'register')->middleware('throttle:client-auth')->name('register');
Route::post('login', 'login')->middleware(['throttle:client-auth', 'turnstile'])->name('login');
Route::post('register', 'register')->middleware(['throttle:client-auth', 'turnstile'])->name('register');
Route::post('verify-email', 'verifyEmail')->middleware('throttle:client-auth')->name('verify-email');
Route::post('resend-verify', 'resendVerifyCode')->middleware('throttle:client-auth')->name('resend-verify');
Route::post('refresh', 'refresh')->name('refresh');
Route::post('forgot-password', 'forgotPassword')->middleware('throttle:client-auth')->name('forgot-password');
Route::post('reset-password', 'resetPassword')->middleware('throttle:client-auth')->name('reset-password');
Route::post('forgot-password', 'forgotPassword')->middleware(['throttle:client-auth', 'turnstile'])->name('forgot-password');
Route::post('reset-password', 'resetPassword')->middleware(['throttle:client-auth', 'turnstile'])->name('reset-password');
// Ảnh CCCD nằm trên disk private, chỉ truy cập qua URL ký (ClientResource cấp, hết hạn 60 phút)
Route::get('cccd/{customer}/{side}', 'cccdImage')
->whereNumber('customer')
@@ -50,6 +50,8 @@ Route::prefix('v1')
Route::get('me', 'me')->name('me');
Route::post('logout', 'logout')->name('logout');
Route::put('update', 'update')->name('update');
Route::get('login-history', 'loginHistory')->name('login-history');
Route::put('preferences', 'updatePreferences')->name('preferences.update');
Route::post('update-cccd', 'updateCccd')->name('update-cccd');
Route::put('change-password', 'changePassword')->name('change-password');
});
@@ -195,6 +197,9 @@ Route::prefix('v1')
Route::controller(SettingController::class)->group(function () {
Route::get('/', 'getSetting')->name('get');
Route::get('email', 'getEmailSetting')->name('email');
Route::get('turnstile', 'getTurnstileSetting')->name('turnstile');
Route::get('menu', 'getMenu')->name('menu');
Route::get('quick-links', 'getQuickLinks')->name('quick-links');
});
});