設定
Lase の設定は config/lase.php で管理します。アプリ側でオーバーライド可能です。
設定ファイルの公開
php artisan vendor:publish --provider="CodebaseJp\Lase\LaseServiceProvider" --tag=config設定項目
IP アクセス制限
管理画面へのアクセスを特定 IP アドレスに限定します。
'ip_restriction' => [
'enabled' => env('IP_RESTRICTION_ENABLED', false),
'allowlist' => explode(',', env('IP_RESTRICTION_ALLOWLIST', '')),
],.env での設定例:
IP_RESTRICTION_ENABLED=true
IP_RESTRICTION_ALLOWLIST=203.0.113.1,203.0.113.2テナント登録の審査
公開の登録フォームから登録されたテナントを、生成AIで審査します(迷惑登録・ブランドの騙りの検出)。判定は記録して管理画面の「登録審査」に出すだけで、テナントを自動では止めません。有効にすると登録ごとに OpenAI(services.openai.api_key)を呼ぶため、既定は無効です。審査はキューで行うため、キューのワーカーが必要です。
'tenant_screening' => [
'enabled' => (bool) env('LASE_TENANT_SCREENING_ENABLED', false),
'model' => env('LASE_TENANT_SCREENING_MODEL', 'gpt-6-luna'),
'reasoning_effort' => env('LASE_TENANT_SCREENING_REASONING_EFFORT', 'none'),
'timeout' => (int) env('LASE_TENANT_SCREENING_TIMEOUT', 30),
'review_threshold' => (int) env('LASE_TENANT_SCREENING_REVIEW_THRESHOLD', 50),
],modelは Responses API で構造化出力(JSON Schema)に対応したモデルを指定しますreasoning_effortを空にすると推論の深さを送りません(推論の指定を受け付けないモデル向け)review_threshold以上の点数を「要確認」にします(0〜100)
認証まわりの制限
ログイン・サインアップ・本登録・パスワードリセットは、パスワードの総当たりを防ぐため回数を制限しています(throttle:lase-auth)。メールアドレスを送るリクエストは「メールアドレス+IP」ごとに1分あたり rate_limit_per_minute 回まで、あわせてIPごとにその6倍まで受け付けます。
'auth' => [
'rate_limit_per_minute' => (int) env('LASE_AUTH_RATE_LIMIT_PER_MINUTE', 5),
],
'recaptcha' => [
'secret_key' => env('RECAPTCHA_SECRET_KEY'),
'score_threshold' => (float) env('RECAPTCHA_SCORE_THRESHOLD', 0.5),
],- IPで制限するため、ロードバランサーの後ろで動かす場合は
TrustProxiesを設定して実際の接続元IPが取れるようにします - 社内NATなどで同じIPから多くのユーザーがログインする環境では、
LASE_AUTH_RATE_LIMIT_PER_MINUTEを緩めます - reCAPTCHA は v3 のスコアが
score_threshold未満のリクエストを拒否します。RECAPTCHA_SECRET_KEYが未設定なら検証しません
フロントエンドのログの出力先
フロントエンドのエラーは POST /api/logger でサーバーのログに記録します。このAPIは認証なしで呼べるため、Slack などに通知するチャンネルに流すと、第三者が通知の文面を書き込めてしまいます。通知しないチャンネルを指定することを推奨します(未設定ならアプリの既定のチャンネル)。
LASE_CLIENT_LOG_CHANNEL=daily受け付ける件数は、IPごと・レベルごとに1分あたりで制限します。同じ回線から多くの端末が INFO を送るアプリは、info を緩めます。レベルごとに数えるため、INFO が上限に達しても WARNING・ERROR は記録されます。
# INFO・DEBUG の上限(既定 120)
LASE_CLIENT_LOG_INFO_RATE_LIMIT_PER_MINUTE=120
# WARNING・ERROR の上限(既定 30)
LASE_CLIENT_LOG_ERROR_RATE_LIMIT_PER_MINUTE=30ドメイン
セッションに使用するドメインを指定します。テナントのサブドメイン認証に利用されます。
'domain' => env('SESSION_DOMAIN', null),アプリ独自のリレーションの追加
ユーザーやテナントに、アプリ独自のリレーション(hasOne)を追加し、ログイン中のユーザーの情報(GET /api/auth/me)に含められます。サーバー側の models と resources、フロントエンド側の登録の3つをそろえます。
// config/lase.php
'models' => [
// Lase のモデルに追加するリレーション(名前 => モデル)。ログイン中のユーザーの取得時に読み込まれる
'user' => ['relations' => ['host' => \App\Models\Host::class]],
'tenant' => ['relations' => ['setting' => \App\Models\Setting::class]],
],
'resources' => [
// 読み込んだリレーションの出力(名前 => リソース)
'user' => ['relations' => ['host' => \App\Http\Resources\HostResource::class]],
'tenant' => ['relations' => ['setting' => \App\Http\Resources\SettingResource::class]],
],フロントエンドのモデルは定義に無い項目を捨てるため、テナントのリレーションは Tenant.registerRelation() で登録します(ユーザーは Actor.register())。ログイン中のユーザーを取得する前に登録すること。
import { Tenant } from '@codebase-jp/lase/models';
import Setting from './models/Setting';
Tenant.registerRelation('setting', Setting); // tenant.setting が Setting.fromApi() で変換されるテナントに所属しない立場でのログイン
テナントへの所属(TenantUser)はテナント管理画面の利用者を意味します。テナント管理画面は使わないがテナントのサブドメインで動く画面を使う立場(例: イベントの主催者)のユーザーを所属させると、テナント管理画面とその API まで使えてしまいます。
こうした立場は CodebaseJp\Lase\Contracts\TenantLoginActor を実装して登録し、所属させずにテナントへログインさせます。
// app/Auth/HostLoginActor.php
class HostLoginActor implements TenantLoginActor
{
public function canLogin(User $user, Tenant $tenant): bool
{
return Host::where('tenant_id', $tenant->id)->where('user_id', $user->id)->exists();
}
}// config/lase.php
'tenant_login_actors' => [
'host' => \App\Auth\HostLoginActor::class,
],// トークンの発行(メインドメイン側のアプリのAPI)
$token = app(TenantLoginTokenService::class)->issue($user, $tenant, $remember, 'host');
// フロントは {tenant}.{domain}/login-by-token/{token}?redirectTo=/host へ遷移させるcanLogin()はトークンの発行時とログイン時の両方で呼ばれます- この立場でログインしたユーザーはテナントに所属していないため、
authorize:tenant/tenant.canを通るテナント管理 API は使えません。立場の画面の API はアプリ側で認可してください - トークンのキャッシュを直接読み書きせず、必ず
TenantLoginTokenServiceを使ってください(緊急停止中のテナントの確認などを通すため)
Enum の差し替え
アプリ固有の Feature や Metric Enum を差し替えられます。
'enums' => [
'tenant_permission' => \App\Enums\TenantPermission::class,
'feature' => \App\Enums\Feature::class,
'metric' => \App\Enums\Metric::class,
],