security(auth): P0 認證安全強化

- Token 過期時間設為 7 天(sanctum.php expiration)
- prune-expired 每日排程清除過期 token 記錄
- Google OAuth redirect 改用 URL fragment(#token=)避免 token 出現在 server log
- SocialAuthController env() 改 config() 修正 config:cache 下 redirect 失效問題
- 登入端點加 rate limiting:member/provider throttle:5,1,admin throttle:3,1
- axios/coachAxios 加 401 response interceptor,token 過期自動登出
- 修正 migration SQLite 相容性(MODIFY COLUMN),Feature tests 從 7 通過恢復至 41
- 新增 AuthRateLimitTest(5 tests)驗證各角色頻率限制行為

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 01:54:40 +08:00
parent 8d1ea49abc
commit cb9c9a9385
22 changed files with 502 additions and 10 deletions
@@ -19,7 +19,7 @@ return new class extends Migration
$table->timestamp('email_verified_at')->nullable(); // 驗證郵件時間
$table->string('password'); // 密碼
$table->string('phone')->nullable(); // 電話號碼,可為空
$table->enum('role', ['admin', 'coach', 'member'])->default('member'); // 角色:管理員、教練、會員
$table->enum('role', ['admin', 'coach', 'member', 'provider'])->default('member'); // 角色:管理員、教練、會員、服務提供者
$table->boolean('is_active')->default(true); // 是否啟用
$table->rememberToken(); // 記住我 token
$table->timestamps(); // 建立與更新時間
@@ -12,11 +12,17 @@ return new class extends Migration
*/
public function up(): void
{
if (DB::getDriverName() === 'sqlite') {
return;
}
DB::statement("ALTER TABLE users MODIFY COLUMN role ENUM('admin', 'coach', 'member', 'provider') NOT NULL DEFAULT 'member'");
}
public function down(): void
{
if (DB::getDriverName() === 'sqlite') {
return;
}
DB::statement("ALTER TABLE users MODIFY COLUMN role ENUM('admin', 'coach', 'member') NOT NULL DEFAULT 'member'");
}
};