特性:增加创始人专享的在线 SMTP 配置系统并在 AppServiceProvider 中动态加载以拦截系统发件
This commit is contained in:
84
app/Http/Controllers/Admin/SmtpController.php
Normal file
84
app/Http/Controllers/Admin/SmtpController.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:系统邮件 SMTP 专属配置控制器
|
||||
*
|
||||
* @author ChatRoom Laravel
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\SysParam;
|
||||
use App\Services\ChatStateService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class SmtpController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ChatStateService $chatState
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 显示 SMTP 专属配置表单
|
||||
*/
|
||||
public function edit(): View
|
||||
{
|
||||
// 仅抓取以 smtp_ 开头的配置项
|
||||
$params = SysParam::where('alias', 'like', 'smtp_%')->pluck('body', 'alias')->toArray();
|
||||
$descriptions = SysParam::where('alias', 'like', 'smtp_%')->pluck('guidetxt', 'alias')->toArray();
|
||||
|
||||
return view('admin.smtp.edit', compact('params', 'descriptions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 SMTP 配置,并刷新全站 Cache 缓存
|
||||
*/
|
||||
public function update(Request $request): RedirectResponse
|
||||
{
|
||||
$data = $request->except(['_token', '_method']);
|
||||
|
||||
foreach ($data as $alias => $body) {
|
||||
SysParam::updateOrCreate(
|
||||
['alias' => $alias],
|
||||
['body' => $body ?? '']
|
||||
);
|
||||
|
||||
// 写入 Cache 保证极速读取
|
||||
$this->chatState->setSysParam($alias, $body ?? '');
|
||||
|
||||
// 清除 Sysparam 模型的内部缓存
|
||||
SysParam::clearCache($alias);
|
||||
}
|
||||
|
||||
return redirect()->route('admin.smtp.edit')->with('success', 'SMTP 发信配置已成功保存更新!');
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送测试邮件
|
||||
*/
|
||||
public function test(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'test_email' => 'required|email'
|
||||
]);
|
||||
|
||||
$testEmail = $request->input('test_email');
|
||||
|
||||
try {
|
||||
Mail::raw('您好,这是一封来自【飘落流星聊天室】系统的测试邮件,当您看到这封邮件,说明系统后台您的 SMTP 设置已经完全畅通无误。', function ($message) use ($testEmail) {
|
||||
$message->to($testEmail)
|
||||
->subject('飘落流星聊天室 - SMTP 发信测试');
|
||||
});
|
||||
|
||||
return redirect()->route('admin.smtp.edit')->with('success', "测试邮件已成功发送至 {$testEmail},请注意查收。");
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('admin.smtp.edit')->with('error', "测试发出失败,原因:" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,12 @@ class SystemController extends Controller
|
||||
{
|
||||
// 读取数据库中最新的参数 (剔除专属模块已接管的配置,避免重复显示)
|
||||
$params = SysParam::whereNotIn('alias', ['chatbot_enabled'])
|
||||
->where('alias', 'not like', 'smtp_%')
|
||||
->get()->pluck('body', 'alias')->toArray();
|
||||
|
||||
// 为后台界面准备的文案对照 (可动态化或硬编码)
|
||||
$descriptions = SysParam::whereNotIn('alias', ['chatbot_enabled'])
|
||||
->where('alias', 'not like', 'smtp_%')
|
||||
->get()->pluck('guidetxt', 'alias')->toArray();
|
||||
|
||||
return view('admin.system.edit', compact('params', 'descriptions'));
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use App\Models\Sysparam;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -19,6 +22,32 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
// 动态加载自定义 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' => null,
|
||||
'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) {
|
||||
// 在安装初期表不存在时忽略,防止应用崩溃
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,11 @@
|
||||
@if (Auth::id() === 1)
|
||||
<a href="{{ route('admin.system.edit') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.system.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
⚙️ 系统参数参数
|
||||
⚙️ 聊天室参数设置
|
||||
</a>
|
||||
<a href="{{ route('admin.smtp.edit') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.smtp.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
📧 邮件 SMTP 配置
|
||||
</a>
|
||||
@endif
|
||||
<a href="{{ route('admin.users.index') }}"
|
||||
|
||||
143
resources/views/admin/smtp/edit.blade.php
Normal file
143
resources/views/admin/smtp/edit.blade.php
Normal file
@@ -0,0 +1,143 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('title', '发件系统 (SMTP) 配置')
|
||||
|
||||
@section('content')
|
||||
<div class="bg-amber-50 border border-amber-200 rounded-xl mb-6 p-4 flex gap-4 shadow-sm items-start">
|
||||
<div class="text-amber-500 text-xl mt-0.5">⚠️</div>
|
||||
<div>
|
||||
<h3 class="font-bold text-amber-800">重要安全警示:最高安全级别配置</h3>
|
||||
<p class="text-sm text-amber-700 mt-1">
|
||||
本页面用于配置支持全站消息推送、密码找回等关键业务的底层 SMTP 邮件网关接口。<br>
|
||||
由于涉及关键的授权密码/秘钥安全,**该界面已被系统强制锁定仅允许 ID=1 的系统创始人操作**。请确保填写的服务器、账号、授权码准确无误。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col md:flex-row gap-6">
|
||||
|
||||
<!-- 配置表单区 -->
|
||||
<div class="flex-1 bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||
<div class="p-5 border-b border-gray-100 bg-gray-50">
|
||||
<h2 class="text-lg font-bold text-gray-800 flex items-center gap-2">
|
||||
<span>📧</span> 编辑 SMTP 发件参数
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<form action="{{ route('admin.smtp.update') }}" method="POST">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="space-y-5">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1">
|
||||
SMTP 服务器地址 <span class="text-gray-400 font-normal ml-1">[smtp_host]</span>
|
||||
</label>
|
||||
<input type="text" name="smtp_host" value="{{ $params['smtp_host'] ?? '' }}"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2 border bg-gray-50"
|
||||
placeholder="例如: smtp.qq.com">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1">
|
||||
SMTP 端口号 <span class="text-gray-400 font-normal ml-1">[smtp_port]</span>
|
||||
</label>
|
||||
<input type="text" name="smtp_port" value="{{ $params['smtp_port'] ?? '465' }}"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2 border bg-gray-50"
|
||||
placeholder="例如: 465 或 25">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1">
|
||||
发件邮箱账号 <span class="text-gray-400 font-normal ml-1">[smtp_username]</span>
|
||||
</label>
|
||||
<input type="text" name="smtp_username" value="{{ $params['smtp_username'] ?? '' }}"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2 border bg-gray-50"
|
||||
placeholder="例如: xxx@qq.com">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1">
|
||||
授权密码 <span class="text-gray-400 font-normal ml-1">[smtp_password]</span>
|
||||
</label>
|
||||
<input type="password" name="smtp_password" value="{{ $params['smtp_password'] ?? '' }}"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2 border bg-gray-50"
|
||||
placeholder="如果是 QQ 邮箱请填写授权码">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1">
|
||||
发送者标记邮箱 <span class="text-gray-400 font-normal ml-1">[smtp_from_address]</span>
|
||||
</label>
|
||||
<input type="text" name="smtp_from_address"
|
||||
value="{{ $params['smtp_from_address'] ?? '' }}"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2 border bg-gray-50"
|
||||
placeholder="通常填与账号一样的邮箱">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1">
|
||||
发送者昵称 <span class="text-gray-400 font-normal ml-1">[smtp_from_name]</span>
|
||||
</label>
|
||||
<input type="text" name="smtp_from_name"
|
||||
value="{{ $params['smtp_from_name'] ?? '飘落流星聊天室' }}"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2 border bg-gray-50"
|
||||
placeholder="邮件中显示的发送者名字">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1">
|
||||
加密方式 <span class="text-gray-400 font-normal ml-1">[smtp_encryption]</span>
|
||||
</label>
|
||||
<select name="smtp_encryption"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2 border bg-gray-50">
|
||||
<option value="ssl" {{ ($params['smtp_encryption'] ?? '') === 'ssl' ? 'selected' : '' }}>
|
||||
SSL加密 (推荐)</option>
|
||||
<option value="tls" {{ ($params['smtp_encryption'] ?? '') === 'tls' ? 'selected' : '' }}>
|
||||
TLS加密</option>
|
||||
<option value="" {{ ($params['smtp_encryption'] ?? '') === '' ? 'selected' : '' }}>无加密
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 pt-5 border-t">
|
||||
<button type="submit"
|
||||
class="px-5 py-2.5 bg-indigo-600 text-white rounded-md font-bold hover:bg-indigo-700 shadow-sm transition w-full md:w-auto">
|
||||
💾 保存 SMTP 发件设置
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 连通性测试区 -->
|
||||
<div class="w-full md:w-1/3 bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden self-start">
|
||||
<div class="p-5 border-b border-gray-100 bg-gray-50">
|
||||
<h2 class="text-lg font-bold text-gray-800 flex items-center gap-2">
|
||||
<span>📡</span> 线路连通性测试
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<p class="text-sm text-gray-500 mb-4 line-clamp-3">
|
||||
配置保存完毕后,请在下方输入一个你能立即查收的外部邮箱地址(如网易/新浪等),系统将尝试发送一封包含成功验证的测试函。</p>
|
||||
<form action="{{ route('admin.smtp.test') }}" method="POST">
|
||||
@csrf
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1">接收测试邮件的地址</label>
|
||||
<input type="email" name="test_email" required
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2 border bg-gray-50 mb-3"
|
||||
placeholder="例如: test@163.com">
|
||||
<button type="submit"
|
||||
class="w-full px-4 py-2 border border-indigo-600 text-indigo-600 rounded-md font-bold hover:bg-indigo-50 transition flex justify-center items-center gap-2">
|
||||
<span>🚀 立即发送测试邮件</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -109,6 +109,11 @@ Route::middleware(['chat.auth', 'chat.level:super'])->prefix('admin')->name('adm
|
||||
Route::middleware(['chat.site_owner'])->group(function () {
|
||||
Route::get('/system', [\App\Http\Controllers\Admin\SystemController::class, 'edit'])->name('system.edit');
|
||||
Route::put('/system', [\App\Http\Controllers\Admin\SystemController::class, 'update'])->name('system.update');
|
||||
|
||||
// 发信配置管理
|
||||
Route::get('/smtp', [\App\Http\Controllers\Admin\SmtpController::class, 'edit'])->name('smtp.edit');
|
||||
Route::put('/smtp', [\App\Http\Controllers\Admin\SmtpController::class, 'update'])->name('smtp.update');
|
||||
Route::post('/smtp/test', [\App\Http\Controllers\Admin\SmtpController::class, 'test'])->name('smtp.test');
|
||||
});
|
||||
|
||||
// 用户大盘管理 (替代 gl/ 目录下的各种用户管理功能)
|
||||
|
||||
Reference in New Issue
Block a user