star-cloud/app/Http/Controllers/Auth/TenantLoginController.php
sky121113 5dd3b0a005 [FEAT] 新增多租戶自訂登入、視覺設定與 APK 版本上傳時間
1. 實作多租戶專屬自訂登入頁面:支援 `/c/{company_code}/login` 特殊入口,自動載入租戶專屬 Logo 網址、名稱與歡迎詞。
2. 支援客製化品牌視覺設定:於客戶管理清單中,提供 SaaS 管理者可自訂租戶 Logo 圖片與歡迎副標題,且系統後台 Header/Sidebar 與登入頁能動態依該配置載入租戶專屬商標。
3. 擴充多語系字典並完成三檔對齊:新增 "Upload Time" 欄位與翻譯,執行 `ksort` 以維持 zh_TW、en 與 ja 語系檔對齊。
4. APK 版本清單增加上傳時間欄位:於 APK 版本表格中呈現上傳時間(created_at),使用 font-mono 奢華風小尺寸樣式呈現。
2026-06-01 17:07:20 +08:00

98 lines
3.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\System\Company;
use App\Models\System\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
class TenantLoginController extends Controller
{
/**
* 顯示專屬客戶的客製化登入頁面
*/
public function showLoginForm($company_code)
{
// 1. 查詢啟用的公司
$company = Company::active()->where('code', $company_code)->first();
// 2. 安全防護:若公司不存在,或沒有啟用品牌客製化功能授權,一律自動重導向至通用登入頁
if (!$company) {
return redirect()->route('login');
}
$settings = $company->settings ?? [];
$enableCustomBranding = filter_var($settings['enable_custom_branding'] ?? false, FILTER_VALIDATE_BOOLEAN);
if (!$enableCustomBranding) {
Log::warning("Tenant login attempted for unauthorized company [{$company_code}]. Redirecting to main login.");
return redirect()->route('login');
}
// 3. 渲染共用的 login Blade傳入當前公司的上下文
return view('auth.login', compact('company'));
}
/**
* 處理專屬客戶的登入請求 (安全性加強版)
*/
public function login($company_code, Request $request)
{
// 1. 查詢並確認該公司
$company = Company::active()->where('code', $company_code)->first();
if (!$company) {
return redirect()->route('login');
}
$settings = $company->settings ?? [];
$enableCustomBranding = filter_var($settings['enable_custom_branding'] ?? false, FILTER_VALIDATE_BOOLEAN);
if (!$enableCustomBranding) {
return redirect()->route('login');
}
// 2. 驗證輸入欄位
$request->validate([
'username' => 'required|string',
'password' => 'required|string',
]);
// 3. 查詢使用者
$user = User::where('username', $request->username)->first();
// 4. 【關鍵安全防錯】驗證此使用者是否確實屬於該公司
if (!$user || $user->company_id !== $company->id) {
Log::warning("Tenant login security violation: User [{$request->username}] attempted login at company [{$company_code}] portal.");
return back()->withErrors([
'username' => __('This account does not belong to this company.'),
])->withInput($request->only('username', 'remember'));
}
// 5. 驗證帳號狀態
if ($user->status !== 1) {
return back()->withErrors([
'username' => __('Your account is disabled.'),
])->withInput($request->only('username', 'remember'));
}
// 6. 驗證密碼
if (!Hash::check($request->password, $user->password)) {
return back()->withErrors([
'password' => __('auth.failed'),
])->withInput($request->only('username', 'remember'));
}
// 7. 執行登入與安全 Session 重新生成
Auth::login($user, $request->boolean('remember'));
$request->session()->regenerate();
Log::info("User [{$user->username}] successfully logged in via company portal [{$company_code}].");
return redirect()->intended(route('admin.dashboard'));
}
}