Search code examples
laravelauthenticationroutessubdomainmiddleware

Using 'auth' middleware with subdomains


I am attempting to pass certain functions in my Controller through the auth middleware. However, the routes associated with these functions require a subdomain in the URL to work. The functions seem to work when they are not passed through middleware or when they are passed through custom made middleware, but the 'auth' middleware throws the error:

UrlGenerationException in UrlGenerationException.php line 17: Missing required parameters for [Route: login] [URI: login].

This is similar to the error that is thrown when I try to run a function without the $account variable in the parameter list (since it is expecting a subdomain with the route).

Upon looking deeper into the Authenticate class that is being called by the 'auth' middleware, I have found that the line that is causing the error is in public function authenticate(array $guards) as shown below.

protected function authenticate(array $guards)

{
    if (empty($guards)) {
        /** ANYTHING BEFORE THIS RETURN STATEMENT RUNS WITH NO ERRORS **/
        return $this->auth->authenticate();
    }

    foreach ($guards as $guard) {
        if ($this->auth->guard($guard)->check()) {
            return $this->auth->shouldUse($guard);
        }
    }

    throw new AuthenticationException('Unauthenticated.', $guards);
}

Here is some of my code for reference (only relevant snippets of the code will be included):

Routes Files

routes\web.php

Route::group(['domain' => '{account}.'.env('APP_URL')], function () {
  include('appRoutes/bcm.php');
});

routes\appRoutes\bcm.php

/********************************************/
/*********STATIC PAGE ROUTES******************/
/********************************************/

Route::get('/boards-commissions', 'BCM\PagesController@home');


/********************************************/
/*********BOARD ROUTES***********************/
/********************************************/

Route::get('/boards-commissions/boards', 'BCM\BoardsController@index');

Route::get('/boards-commissions/boards/archive/index', 
'BCM\BoardsController@archiveIndex');

Controllers

app\Http\Controllers\BCM\BoardsController.php

namespace App\Http\Controllers\BCM;

use Auth;
use Session;
use Validator;

use Illuminate\Http\Request;
use Illuminate\Foundation\Validation\ValidatesRequests;

//Models
use App\Models\BCM\Board;

class BoardsController extends Controller
{
    public function __construct()
    {
        $this->middleware('bcm_app_access');
        $this->middleware('auth', ['except' => array('index', 'show')]);
        $this->middleware('bcm_admin', ['only' => array('edit', 'update', 
'create', 'store', 'archive', 'showArchive', 'showArchivedBoard', 'restore')]);
    }

    public function index($account, Request $request) {
        $boards = Board::all();
        $user = $request->user();
        return view('bcm.boards.index')->with('boards', $boards)->with('user', $user);
    }

    public function archiveIndex($account, Request $request) {
        $boards = Board::all();
        $user = $request->user();
        return view('bcm.boards.archiveList')->with('boards', $boards)->with('user', $user);
    }
}

It seems to be only the auth middleware that is not working so far. The index function runs just fine (since it is being excluded from the auth middleware in the construct of the controller) even though it is being passed through the bcm_app_access middleware. But archiveIndex will throw the UrlGenerationException error mentioned above when it passes through the auth middleware.

I have a feeling that the $account parameter needs to be added or included somewhere so that the auth middleware knows that it needs to reference it but I'm not sure where to add that in and I don't know what other files are being referenced when $this->auth->authenticate(); is run so I don't know where to add that in. Any thoughts?


Solution

  • In the original question I wanted to know how to get the 'auth' middleware to work with subdomains. I still haven't figured out to do that but I have established a functional work-around by creating a basic custom middleware. The point of the authenticate middleware was to check whether a user of the site was logged in or running as a guest. To mimic this functionality, I created a middleware by running

    php artisan make:middleware SubdomainAuth
    

    in command line. Then I configured the auto-generated middleware file to look as follows:

    <?php
    namespace App\Http\Middleware;
    use Closure;
    use Auth;
    class SubdomainAuth
    {
        /**
         * Handle an incoming request to make sure that a valid user is logged in.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next) {
            $user = Auth::user();
            if ($user == null) {
              return redirect('/login');
            }
            return $next($request);
        }
    }
    

    Lastly, I configured my Kernel to recognize the new middleware by adding the line

    'sub_auth' => \App\Http\Middleware\SubdomainAuth::class,
    

    to app/Http/Kernel.php. From there I was able to replace the auth middleware in my controllers with the sub_auth middleware that I created. My example from the question above now looks like this:

    namespace App\Http\Controllers\BCM;
    
    use Auth;
    use Session;
    use Validator;
    
    use Illuminate\Http\Request;
    use Illuminate\Foundation\Validation\ValidatesRequests;
    
    //Models
    use App\Models\BCM\Board;
    
    class BoardsController extends Controller
    {
        public function __construct()
        {
            $this->middleware('bcm_app_access');
            $this->middleware('sub_auth', ['except' => array('index', 'show')]);
            $this->middleware('bcm_admin', ['only' => array('edit', 'update', 
    'create', 'store', 'archive', 'showArchive', 'showArchivedBoard', 'restore')]);
        }
    
        public function index($account, Request $request) {
            $boards = Board::all();
            $user = $request->user();
            return view('bcm.boards.index')->with('boards', $boards)->with('user', $user);
        }
    
        public function archiveIndex($account, Request $request) {
            $boards = Board::all();
            $user = $request->user();
            return view('bcm.boards.archiveList')->with('boards', $boards)->with('user', $user);
        }
    }
    

    This work-around successfully screens those who are not logged in and redirects them to the login page. However, I am not familiar enough with how the Authenticate middleware works to know if there is any added security that my custom class is missing in the SubdomainAuth class I created.