【Laravel】Laravel5.5でユーザーと管理者の認証（MultiAuth）を実装する（マルチログイン実装時のセッション分割対応）


# セッションが衝突する

色々な方法がネット上にありますが、MultiAuthを実装した際に発生する問題として、
**ユーザーと管理者でログインした際に適切なリダイレクト処理が行われない**
（例えば**ユーザーはMyPage**へ、**管理者は管理画面TOP**へリダイレクト処理が行われるはずが**それぞれ異なるページへリダイレクト処理が行われたりする**）
という問題が起こったので、**セッションをそれぞれ分離する**やり方で実装してみました。

ほぼほぼ以下のサイト様を参考に実装しましたので詳細は↓を参照してください。
つ  [Laravel 5.6 で multi-auth の実装 | CORGI, Inc.](https://www.tech-corgi.com/laravel5-6-multi-auth/)

# 実装例

## configディレクトリ以下の設定

`session.php`と`auth.php`を少し触ります。

```php:session.php
<?php

$sessConf = [

    /*
    |--------------------------------------------------------------------------
    | Default Session Driver
    |--------------------------------------------------------------------------
    |

～～～～～～～～～

    /*
    |--------------------------------------------------------------------------
    | Same-Site Cookies
    |--------------------------------------------------------------------------
    |
    | This option determines how your cookies behave when cross-site requests
    | take place, and can be used to mitigate CSRF attacks. By default, we
    | do not enable this as other CSRF protection services are in place.
    |
    | Supported: "lax", "strict"
    |
    */

    'same_site' => null,

];

$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';

// 管理者側用セッション
if (strstr($uri, '/admin/') !== false || $uri === '/admin/login') {
    $sessConf['cookie'] = env(
        'SESSION_COOKIE_ADMIN',
        str_slug(env('APP_NAME', 'laravel'), '_').'_admin_session'
    );
}

return $sessConf;
```

```php:auth.php
<?php

$authConf = [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'user',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session", "token"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
        // 以下userとadmin用に追加
        'user' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Admin::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that the reset token should be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
        ],
        'admins' => [
            'provider' => 'admins',
            'table' => 'password_resets',
            'expire' => 60,
        ],
    ],

];

$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';

// 管理者側の認証ガード設定
if (strstr($uri, '/admin/') !== false || $uri === '/admin/login') {
    $authConf['defaults'] = [
        'guard'     => 'admin',
        'passwords' => 'admins',
    ];
}

return $authConf;
```

## Handlerの設定

```\app\Exceptions\Handler.php
    /**
     * Convert an authentication exception into an unauthenticated response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Illuminate\Auth\AuthenticationException  $exception
     * @return \Illuminate\Http\Response
     */
    protected function unauthenticated($request, AuthenticationException $exception)
    {
        $redirectTo = in_array('admin', $exception->guards(), true) ? 'admin.login' : 'login';

        return $request->expectsJson()
                    ? response()->json(['message' => $exception->getMessage()], 401)
                    : redirect()->guest(route($redirectTo));
    }
```

## RedirectIfAuthenticatedの設定
ここでユーザーと管理者でログイン後のリダイレクト先を変える

```php:\app\Http\Middleware\RedirectIfAuthenticated.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class RedirectIfAuthenticated
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        $redirectTo = "/home";

        // 管理者なら管理画面用ホームのパスを設定する
        if ($guard === "admin") {
            $redirectTo = "/admin/home";
        }

        if (Auth::guard($guard)->check()) {
            return redirect($redirectTo);
        }

        return $next($request);
    }
}
```

## `.env`ファイル設定
`.env`ファイルにユーザー用と管理者用のCookieをそれぞれ別で設定

```:.env
SESSION_COOKIE=hogehoge_user
SESSION_COOKIE_ADMIN=hogehoge_admin
```

# おわり
- もっといい方法あれば教えていただきたいです草々不一

# 参考サイト
- [Laravel 5.6 で multi-auth の実装 | CORGI, Inc.](https://www.tech-corgi.com/laravel5-6-multi-auth/)