ユーザー認証(10)Laravel 5.2 マルチ認証では、会員と管理者に対して異なるDBテーブルをもとに認証を設定しました。
また、
前回では、違うHasherの使用を試みました。
今回は、マルチ認証のときに異なるHasherを用いるケースについて考えてみましょう。そうたくさん起こるケースでないかもしれませんが、私のクライアントのシステムでは実際に起こるケースです。1つのシステムにおいて、「会員」と「管理者」と「店舗管理者」が存在し、それぞれの認証は異なるHasherを使用しています。特に「管理者」は複数のシステムで共有するもので、その認証のためのサーバーが違うマシンに存在します。
まず直面する問題は、Laravelの5.2のマルチ認証では、このような状況にはシンプルに対応できないことです。
config/auth.phpのprovidersでは、それぞれのproviderにおいてhasherの設定がないのです。
..
   'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
        'admin_users' => [
            'driver' => 'eloquent',
            'model' => App\AdminUser::class,
        ],
    ],
..
また、前回のように、グローバルでHasherを変えることもできません。
「会員」の認証のときには、デフォルトのHasherを使用し、「管理者」の認証のときには、違うHasherを使用できるのが理想です。
まず、Authのサービスがどう初期化されているか追跡してみましょう。
AuthServiceProviderで、ユーザー認証のサービスauthが登録されます。そこでは、AuthManagerのクラスが使用されます。
  protected function registerAuthenticator()
    {
        $this->app->singleton('auth', function ($app) {
            $app['auth.loaded'] = true;
            return new AuthManager($app);
        });
        $this->app->singleton('auth.driver', function ($app) {
            return $app['auth']->guard();
        });
    }
AuthManagerでは、config/auth.phpの設定を読み込み、providerを作成します。その作成は、CreatesUserProvidersで行われます。
..
    public function createSessionDriver($name, $config)
    {
        $provider = $this->createUserProvider($config['provider']);
..
providerのdriverは、先のconfig/auth.phpではeloquentと設定されているので、以下のメソッドでオブジェクトが作成されます。
..
   protected function createEloquentProvider($config)
    {
        return new EloquentUserProvider($this->app['hash'], $config['model']);
    }
..
やっとたどり着きましたね。そうproviderの作成時に、グローバルのHasher app['hash']がパラメとして渡されているのです。
ここを変えることができれば、認証のHasherを変えることできるのです。変更するには、新規の認証のためのdriverを使用することも可能です。しかし、以下のEloquentUserProviderを見ると、オブジェクトが作成された後でもHasherを変えることが可能のようです。
...
    /**
     * Sets the hasher implementation.
     *
     * @param  \Illuminate\Contracts\Hashing\Hasher  $hasher
     * @return $this
     */
    public function setHasher(HasherContract $hasher)
    {
        $this->hasher = $hasher;
        return $this;
    }
...
ここまで理解すると、あとはそう難しくはありません。
まずは、config/auth.phpにおいて、どのHasherのサービスを使用するか指定しましょう。
...
   'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
       'hasher' => Illuminate\Hashing\BcryptHasher::class
        ],
        'admin_users' => [
            'driver' => 'eloquent',
            'model' => App\AdminUser::class,
            'hasher' => App\Services\MD5Hasher::class
        ],
    ],
...
上のhasherはまったくLaravelのコードでは使用されませんが、今回の目的でHasherを指定するにはベストの場所と思いませんか!
次に、管理者のAuthControllerにおいて、
...
class AuthController extends Controller
{
    use AuthenticatesAndRegistersUsers, ThrottlesLogins {
        getCredentials as getCredentialsTrait;
    }
    protected $redirectTo = '/admin/home';
    protected $guard = 'admin';
    protected $redirectAfterLogout = 'admin/login'; //ログイン後のリダイレクト先
    protected $username = 'email'; // DBテーブルのログインに使用される項目
    protected $registerView = 'admin.auth.register'; // 登録に使用されるテンプレート
    protected $loginView = 'admin.auth.login'; // ログインに使用されるテンプレート
    protected $hasher;
    public function __construct()
    {
        $hasher_class = config('auth.providers.admin_users.hasher');
        $this->hasher = new $hasher_class;
        \Auth::guard($this->guard)->getProvider()->setHasher($this->hasher);
        $this->middleware('guest:admin', ['except' => 'logout']);
    }
...
会員と違うテンプレートを用意するために、テンプレートの場所を指定していることにも注意してください。すべて変数の指定で可能です。
PasswordControllerにおいても同様な設定をします。
class PasswordController extends Controller
{
    use ResetsPasswords;
    protected $redirectTo = '/admin/home'; // ログイン後のリダイレクト先
    protected $guard = 'admin';
    protected $linkRequestView = 'admin.auth.passwords.email'; // パスワードのリセットリンクを送信してもらう画面のテンプレート
    protected $resetView = 'admin.auth.passwords.reset'; // パスワードリセット画面のテンプレート
    protected $subject = '管理者のパスワードリセット'; // 送信メールの件名
    public function __construct()
    {
        $hasher_class = config('auth.providers.admin_users.hasher');
        \Auth::guard($this->guard)->getProvider()->setHasher(new $hasher_class);
        $this->middleware('guest:admin');
    }
}
最後に、管理者へのパスワードリセットのメールのテンプレートは、以下のように、config/auth.phpで可能です。
...
  'passwords' => [
        'users' => [
            'provider' => 'users',
            'email' => 'user.auth.emails.password',
            'table' => 'password_resets',
            'expire' => 60,
        ],
        'admin_users' => [
            'provider' => 'admin_users',
            'email' => 'admin.auth.emails.password',
            'table' => 'admin_password_resets',
            'expire' => 60,
        ],
    ],
];
メルマガ購読の申し込みはこちらから。        
        