今回はLaravelでサブドメインごとにルーティングを分ける方法を解説します。
Laravelではデフォルトでwebとapiの2つのルーティングが設定されています。
それとは別にサブドメインを使って新しいルーティングを作成したいときは簡単にルーティングを追加することが可能です。
認証もルーティングごとに分けることでマルチログインも対応できます。
管理画面用のルーティング追加を例に進めます。
ルーティングファイルの追加
まず新たに作成したいルーティングファイルを作成します。
routes
ディレクトリ配下にadmin.phpを作成します。
laravel-app
|-routes
|-admin.php ←追加
|-api.php
|-channels.php
|-console.php
|-web.php
ルーティングファイルを作成してルートを記述しても今のままでは404エラーになってしまいます。
<?php
// 存在しないルートのため404エラーになる
Route::get('/hello', function () {
return 'Hello Admin World!';
});
余談ですが、laravel-ide-helperを使えばファサードの保管なども効いてくれて実装が楽になります。
laravel-ide-helperについてはこちらを参考ください。
RouteServiceProviderの設定
ルーティングファイルを作成しただけではそのルートに対してアクセスできないので、RouteServiceProvider
に設定を追加してあげることでadmin.phpに記述されているルートを読み込むようにします。
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* The path to the "home" route for your application.
*
* @var string
*/
public const HOME = '/home';
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
parent::boot();
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapAdminWebRoute(); // 追加
$this->mapApiRoutes();
$this->mapWebRoutes();
}
// ==========ここから==========
protected function mapAdminWebRoute()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/admin.php'));
}
// ==========ここまで追加==========
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
}
先程作成したadmin.phpに対してweb
というミドルウェアを通って通信するということを設定してあげます。
これで先程admin.phpに定義した/hello
というルートに対してアクセスできるようになりました。
サブドメイン設定
定義したルートにアクセスできるようになりましたが、今のままだとどちらのファイルもエンドポイントのドメインが同じになってしまいます。
同じエンドポイントだった場合どちらのファイルにアクセスしているのか気になったため試してみました。
それぞれのファイルで同じエンドポイントを定義しそのエンドポイントに対してリクエストをしてみると、RouteServiceProvider
のmapメソッドで後に定義したルーティングにアクセスしていることがわかりました。
今回の場合だとweb.phpの方にアクセスします。
仮にweb.phpにもadmin.phpで定義したものと全く同じルートを定義するとエラーにはなりませんがバグに繋がりそうです。
public function map()
{
$this->mapAdminWebRoute();
$this->mapApiRoutes();
$this->mapWebRoutes(); // 同じエンドポイントだと後に定義しているこっちにアクセスする
}
別ルートを作成するからにはエンドポイントのドメインは分けるのが普通です。
ここでadmin.phpのルーティングにはサブドメインを設定します。
こうすることでhttp://admin.localhost/hello
にアクセスが可能になります。
仮にweb.phpに同じURIのルートが存在してもドメイン部分が異なるため別エンドポイントとなります。
<?php
Route::domain('admin.' . config('app.domain'))->group(function () {
Route::get('/hello', function () {
return 'Hello Admin World!';
});
});
Routeファサードのdomain
メソッドを使うことでそのルーティングのドメインを指定できます。
今回の場合だとadmin.
に対してconfigに定義しているアプリケーションのドメインを文字列結合しています。
【おまけ】マルチログイン
細かくは解説しませんが、今までのルーティングのを使ってマルチログインも実装できます。
詳しくはこちらが参考になるかと思います。
まず認証の設定を変更します。
auth.phpに対してAdmin用のガードやプロバイダーを追加してあげます。
※Adminモデルが存在する前提で進めています。
<?php
use App\Models\Admin;
use App\Models\User;
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [ // ------------------ 追加
'driver' => 'session',
'provider' => 'admins'
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => User::class,
],
'admins' => [ // ------------------ 追加
'driver' => 'eloquent',
'model' => Admin::class,
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'user_password_resets',
'expire' => 60,
'throttle' => 60,
],
'admins' => [ // ------------------ 追加
'provider' => 'admins',
'table' => 'admin_password_resets',
'expire' => 60,
'throttle' => 60,
]
],
];
Authenticate
というミドルウェアがあるのでそれを使って指定したガードに対して認証しているかを確認し、認証していない状態であればアクセスできなくなります。
このように管理画面用のルーティングとユーザー用のルーティングを分けることが実現できます。
<?php
Route::domain('admin.' . config('app.domain'))->group(function () {
// adminというガードに認証しているか
Route::middleware('auth:admin')->group(function () {
Route::get('/hello', function () {
return 'Hello Admin World!';
});
});
});
<?php
Route::domain(config('app.domain'))->group(function () {
// webというガードに認証しているか
Route::middleware('auth:web')->group(function () {
Route::get('/hello', function () {
return 'Hello World!';
});
});
});
単にサブドメインを切ってルーティングを分けるだけであればそんなに難しいことではなかったですね。
コメント