質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.48%

【Laravel】MultiAuthのサイトでバックドアを実装したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,740

score 101

バックドアという表現が正しいかわかりませんが、ログイン画面を経由せず、ログイン情報を使用せずにログインをさせる方法についてお伺いしたいです。  

管理画面が複数あるサイトを実装しているのですが、
管理画面間を代理でログイン出来るようなシステムを実装したいと考えています。

挙動自体はエラーではないので、エラーページも表示されず、laravelのエラーログにも残りません。 
原因の探り方からでも構いませんのでご教示いただけないでしょうか?

実装したい事の概要

システム管理者とショップ管理者でそれぞれ管理画面の機能があります。  
システム管理者は基本的に増えませんが、ショップはシステム管理者の管理画面から追加します。  

運用上、ショップの作業をシステム管理者が代理で行いたい時もあります。
その時、システム管理者の機能に各ショップにログイン出来る仕組みを導入したいです。

ページ構成

URLとlaravelのルートは以下です。  
本来は、パスワードリマインダーや管理画面の個々の機能もありますが省略します。  

url route 概要
http://hoge.com/admin/login admin.login システム管理者のログイン
http://hoge.com/admin/shops/ admin.shop.index 登録されているスクール一覧。一覧の中に代理ログイン用のURLリンクが追加されます。  
http://hoge.com/admin/shops/{ショップのID}/proxy-login admin.shops.proxy-login 指定したログインIDを元に代理でログインします。ログイン処理後は処理完了後ショップのホーム画面に遷移します。
http://hoge.com/shop/login shop.login 本来のショップのログイン画面です。
http://hoge.com/shop/login shop.logout ショップのログアウト処理を行います。
http://hoge.com/shop/ shop.home ログイン後に自動で遷移するショップのホーム画面です。

認証機能の設定

MultiAuthのサイトなので、gurdとproviderはそれぞれ設定しました。  
下記のように、adminとshopと言う名前で下記のような設定をしています。  

<?php

return [
    'defaults' => [
        'guard' => 'admin',
        'passwords' => 'admins',
    ],

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins'
        ],
        'shop' => [
            'driver' => 'session',
            'provider' => 'shops'
        ]
    ],

    'providers' => [
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Admin::class,
        ],
        'shops' => [
            'driver' => 'eloquent',
            'model' => App\Shop::class,
        ]
    ],
];

セッションについて

管理画面毎にログイン時のセッションが衝突しないように、別のセッション名になるように設定しています。  

use Illuminate\Support\Str;

$defaultSession = Str::slug(
    env('APP_NAME', 'laravel'), '_').'_session';

$conf = [
    (省略)
];

// 管理画面のセッション切り替え
$uri = isset($_SERVER['REQUEST_URI'])
    ? $_SERVER['REQUEST_URI']
    : '';

if(strpos($uri, '/admin/') === 0 || $uri === '/admin') {
    $conf['cookie'] = env(
        'admin_session',
        $defaultSession
    );
} elseif(strpos($uri, '/shop/') === 0 || $uri === '/shop') {
    $conf['cookie'] = env(
        'shop_session',
        $defaultSession
    );
}

代理ログインの処理

管理者のControllerに、ログイン画面から個別のショップにログインする処理を追加しています。  
ガードがadminからshopに変わりますので、ガードを新しく指定して、IDでログイン出来るようにloginUsingIdでログインさせます。  

コントローラーの処理

ルートadmin.shops.proxy-loginで実行される処理が下記です。  

$shop_urlには、ログイン先が検索できる固有のIDが入ります。  
リダイレクト先のルートshop.home では、ミドルウェアでschoolにログイン済みか検証します。  
もしログインされている事を確認できなければ、ログイン画面に遷移します。  

<?php
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;

class ShopController extends Controller
{

    public function __construct()
    {
        $this->middleware('auth:admin');
    }

    public function proxyLogin($shop_url) {

        $shop = shop::where('shop_url', $shop_url);

        // 存在しないURLの場合は元の画面に戻す
        if(! $shop->exists() || $shop->count() > 1 ) {
            return back();
        }

        // ショップ管理画面のログイン
        Auth::guard('shop')->logout();
        Auth::guard('shop')->loginUsingId($shop->first()->id);

        // リダイレクト
        return redirect()->route('shop.home');
    }
}

実際の挙動

ショップのログイン画面にリダイレクトされます。  
そのため、ログイン処理は成功していない事はわかります。  

単純に、ショップの管理画面でログインすると正常にログイン出来ますので、ログイン側の処理に誤りがあるわけではなさそうです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

基本的には、ご記載の方法で(loginUsingIdを使う方法)で合ってると思います。
問題は、セッション名を動的に変えている部分との干渉なのでは、と思います。

proxyLoginが実行されるときはセッション名がshop_sessionではなくadmin_sessionになっているため
admin_sessionにshopのログイン情報が書き込まれるからではないかと思います。
if文を追加するなどして調整してみてはいかがでしょうか


そもそも、shopとadminのセッションが別な理由が
ショップにログインしつつアドミンもログインさせたい、という理由であればMultiAuthの時点で対応している気がします。(衝突しないはず)
なのでセッションについての項目はひょっとして不要で、そこを消せば思惑通り動く気がします

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/05 18:18

    ご回答ありがとうございます。
    セッションの動きについてご説明いただいた内容で頭がクリアになりました。
    確かに、まだadminのセッション内の作業ですね。

    おっしゃる通り、セッション名を分ける処理をなくしたところログインができました。

    キャンセル

+1

ユーザーなりすましとして、UserモデルのonceUsingIdメソッドと、ミドルウェアを組み合わして実現する、以下の記事を参考にしてみてください。
Easily impersonate any user in a Laravel Application

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/05 18:26

    何時もありがとうございます。
    参考サイトを読ませていただきました。
    代理でログインユーザーをsessionで管理して、ユーザーページのrouteにアクセスした際にそのセッションがあればログインするのですね。
    参考になりました。
    ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る