Files

137 lines
4.8 KiB
PHP
Raw Permalink Normal View History

2026-02-26 12:02:00 +08:00
<?php
/**
* 文件功能:应用服务提供者
*
* 负责注册和引导应用级服务:自定义 SMTP 配置动态加载、
* 婚姻系统消息事件订阅者注册等。
*/
2026-02-26 12:02:00 +08:00
namespace App\Providers;
use App\Listeners\SaveMarriageSystemMessage;
use App\Models\Sysparam;
2026-04-19 14:42:42 +08:00
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Event;
2026-04-19 14:42:42 +08:00
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Schema;
2026-04-19 15:15:58 +08:00
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
2026-04-19 14:42:42 +08:00
use Illuminate\Support\Str;
2026-02-26 12:02:00 +08:00
2026-04-19 14:42:42 +08:00
/**
* 类功能:注册应用级服务与全局安全配置。
*/
2026-02-26 12:02:00 +08:00
class AppServiceProvider extends ServiceProvider
{
/**
2026-04-19 14:42:42 +08:00
* 注册应用级服务容器绑定。
2026-02-26 12:02:00 +08:00
*/
public function register(): void
{
//
}
/**
2026-04-19 14:42:42 +08:00
* 引导应用启动阶段的全局配置与事件订阅。
2026-02-26 12:02:00 +08:00
*/
public function boot(): void
{
2026-04-19 15:15:58 +08:00
// 生产环境按配置强制生成 HTTPS 资源链接,避免反代链路下的 Mixed Content。
$this->configureSecureUrls();
2026-04-19 14:42:42 +08:00
// 注册登录入口限流器,阻断爆破和批量注册滥用。
$this->registerAuthRateLimiters();
// 注册婚姻系统消息订阅者(结婚/婚礼/离婚通知写入聊天历史)
Event::subscribe(SaveMarriageSystemMessage::class);
// 动态加载自定义 SMTP 配置 (如果有数据库则执行)
try {
if (Schema::hasTable('sysparam')) {
$smtpConfig = Sysparam::where('alias', 'like', 'smtp_%')->pluck('body', 'alias');
if ($smtpConfig->isNotEmpty() && $smtpConfig->get('smtp_host')) {
Config::set('mail.default', 'smtp');
Config::set('mail.mailers.smtp', [
'transport' => 'smtp',
'host' => $smtpConfig->get('smtp_host'),
'port' => $smtpConfig->get('smtp_port', 465),
'encryption' => $smtpConfig->get('smtp_encryption', 'ssl'),
'username' => $smtpConfig->get('smtp_username'),
'password' => $smtpConfig->get('smtp_password'),
'timeout' => 10,
'local_domain' => env('MAIL_EHLO_DOMAIN'),
]);
Config::set('mail.from', [
'address' => $smtpConfig->get('smtp_from_address', $smtpConfig->get('smtp_username')),
'name' => $smtpConfig->get('smtp_from_name', '飘落流星聊天室'),
]);
}
}
} catch (\Exception $e) {
// 在安装初期表不存在时忽略,防止应用崩溃
}
2026-02-26 12:02:00 +08:00
}
2026-04-19 14:42:42 +08:00
2026-04-19 15:15:58 +08:00
/**
* 根据应用配置决定是否统一强制 HTTPS 方案。
*/
private function configureSecureUrls(): void
{
if (! config('app.force_https')) {
return;
}
URL::forceScheme('https');
}
2026-04-19 14:42:42 +08:00
/**
* 注册聊天室前台登录与隐藏后台登录的独立限流器。
*/
private function registerAuthRateLimiters(): void
{
RateLimiter::for('chat-login', function (Request $request): Limit {
return Limit::perMinute(5)
->by($this->buildAuthRateLimitKey($request, 'chat-login'))
->response(function (Request $request, array $headers) {
return response()->json([
'status' => 'error',
'message' => '登录尝试过于频繁,请 1 分钟后再试。',
], 429, $headers);
});
});
RateLimiter::for('admin-hidden-login', function (Request $request): Limit {
return Limit::perMinute(5)
->by($this->buildAuthRateLimitKey($request, 'admin-hidden-login'))
->response(function (Request $request, array $headers) {
$response = redirect()->route('admin.login')
->withInput($request->except(['password', 'captcha']))
->withErrors(['username' => '登录尝试过于频繁,请 1 分钟后再试。']);
foreach ($headers as $headerName => $headerValue) {
$response->headers->set($headerName, $headerValue);
}
$response->setStatusCode(429);
return $response;
});
});
}
/**
* 构造登录限流键,按场景 + 用户名 + IP 维度隔离计数。
*/
private function buildAuthRateLimitKey(Request $request, string $scene): string
{
$username = Str::lower(trim((string) $request->input('username', 'guest')));
return implode('|', [$scene, $username, $request->ip()]);
}
2026-02-26 12:02:00 +08:00
}