Force Laravel for user login using legacy authentication

I am trying to slowly integrate Laravel into an outdated PHP application. One of the tasks is to automatically register a Laravel user session when a user logs into an old application. I'm not trying to implement Laravel authentication, I just want to compose existing functions and force an individual user to log in without checking credentials. What I have so far been paved with other people I have found around:

// Laravel authentication hook - Boostrap application require_once getcwd() . '/../laravel/bootstrap/autoload.php'; $app = require_once getcwd() . '/../laravel/bootstrap/app.php'; $kernel = $app->make('Illuminate\Contracts\Console\Kernel'); $kernel->bootstrap(); $app->boot(); // Start Laravel session $request = Illuminate\Http\Request::capture(); $response = $app->make('Symfony\Component\HttpFoundation\Response'); $startSession = new Illuminate\Session\Middleware\StartSession($app['session']); // Associate server session with the authenticating user id // I have also tried loading user model instance and then $app['auth']->login($user) $app['auth']->loginUsingId($user_id); $app['session']->driver()->start(); // Terminate middleware response chain with naked response $response = $startSession->handle($request, function() use($response) { return $response; // This response will have session cookie attached to it }); $response->send(); 

After that, I get a laravel_session cookie containing the content on the client. During the login request after executing the above code, if I dd(Auth::user()) , then I get the user with whom I just logged in. However, on subsequent requests, Auth::user() and $this->request->user() both return null in all contexts.

How to force an active Laravel user session without actually authenticating, which will be stored in requests?


The end result is that Laravel will work as a “sub-application” under the old application, while existing functions are pulled one by one, so that both will exist for a certain period of time until all functions are implemented in Laravel and it will completely replace the existing application. If it makes sense to try using outdated authentication with Laravel, and not vice versa, I am open for this, but I would prefer not to change the table of basic users (outdated authentication occurs via LDAP, so there are no passwords locally, there is no remember_token, but it’s easy enough to add if I need to). I am really looking for the shortest path with the least amount of effort / headache.

+8
authentication php laravel legacy
source share
4 answers

This is a bit complicated because Laravel uses encrypted cookies that are processed by the EncryptCookies middleware. You can make your code work if you disable it, but I would not recommend it.

The solution is to use the Laravel EncryptCookies middleware to decrypt the request and then encrypt the response. This will make the session created by your old authentication readable by Laravel.

Suppose this is called a login.php file that needs $user_id to register a user by id on laravel.

 <?php require_once getcwd() . '/../laravel/bootstrap/autoload.php'; $app = require_once getcwd() . '/../laravel/bootstrap/app.php'; $kernel = $app->make('Illuminate\Contracts\Console\Kernel'); $kernel->bootstrap(); $app->boot(); $request = Illuminate\Http\Request::capture(); $response = $app->make('Symfony\Component\HttpFoundation\Response'); $startSession = new Illuminate\Session\Middleware\StartSession($app['session']); $encryptCookies = new App\Http\Middleware\EncryptCookies($app['encrypter']); $app['session']->driver()->start(); $app['auth']->loginUsingId($user_id); $response = $encryptCookies->handle($request, function ($request) use ($startSession, $response) { return $startSession->handle($request, function () use ($response) { return $response; }); }); $app['session']->driver()->save(); var_dump($app['auth']->user()); $response->send(); 

Inside the closure of $encryptCookies->handle() you can read the request after decryption, and here you can change the session. And when you return the answer, it will be encrypted again, and you can send it to the browser.

To read the session in another file, you can simply do this:

 <?php require_once getcwd() . '/../laravel/bootstrap/autoload.php'; $app = require_once getcwd() . '/../laravel/bootstrap/app.php'; $kernel = $app->make('Illuminate\Contracts\Console\Kernel'); $kernel->bootstrap(); $app->boot(); $request = Illuminate\Http\Request::capture(); $response = $app->make('Symfony\Component\HttpFoundation\Response'); $startSession = new Illuminate\Session\Middleware\StartSession($app['session']); $encryptCookies = new App\Http\Middleware\EncryptCookies($app['encrypter']); $response = $encryptCookies->handle($request, function ($request) use ($startSession, $response) { return $startSession->handle($request, function () use ($response) { return $response; }); }); var_dump($app['auth']->user()); $response->send(); 
+1
source share

You do not call save() on the session, so your session is not saved. I changed the last few lines of your code like this:

 // Laravel authentication hook - Boostrap application require_once getcwd() . '/../laravel/bootstrap/autoload.php'; $app = require_once getcwd() . '/../laravel/bootstrap/app.php'; $kernel = $app->make('Illuminate\Contracts\Console\Kernel'); $kernel->bootstrap(); $app->boot(); // Start Laravel session $request = Illuminate\Http\Request::capture(); $response = $app->make('Symfony\Component\HttpFoundation\Response'); $startSession = new Illuminate\Session\Middleware\StartSession($app['session']); // Associate server session with the authenticating user id // I have also tried loading user model instance and then $app['auth']->login($user) $app['auth']->loginUsingId($user_id); $app['session']->driver()->start(); // Terminate middleware response chain with naked response $response = $startSession->handle($request, function() use($response) { return $response; // This response will have session cookie attached to it }); // Added the following two lines var_dump($app['auth']->user()); //This is for debugging $app['session']->driver()->save(); $response->send(); 

I copied this code by deleting only the line $app['auth']->loginUsingId($user_id); , to the second file and launched it, and the dump indicates that the same user is still registered. Logging out and deleting the line that saves the session will stop working. Hope this is the solution you were looking for.

+1
source share

I would advise you to think that Laravel is the main application that allows you to skip legacy code for routes that you have not yet converted. I did this with a huge legacy application that had everything you would expect from an application written 10 years ago, and although it all worked together, it hurt from the very beginning (like the ones you experience, but vice versa) by as it was finished, I just deleted the old code until there was nothing left. With your approach, I cannot understand what will happen when the time comes to permanently undo the old code.

I ended up with:

 /app /Console /Http etc... /old /lib /screens /config index.php 

OldController had a setup with

 /** * Catches all routes for old code * * @codeCoverageIgnore * @return \Illuminate\Http\Response * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function index($all = null) { ob_start(); require __DIR__.'/../../old/index.php'; $html = ob_get_clean(); return response()->string($html); } 

The old / index.php should have done things like:

 // TODO: In place to avoid E_DEPRECATED errors for mysql error_reporting(E_ALL ^ E_DEPRECATED); session_start(); // Allow all hardcoded includes in old/ to work $path = __DIR__; set_include_path(get_include_path() . PATH_SEPARATOR . $path); // Set up the global user to suit old code if (Auth::user()) { $myUser = Auth::user()->toArray(); $myUser['requests'] = getRequestList($myUser['uid']); $loggedin = true; Log::debug('using Auth::user() id ' . $myUser['uid']); } else { $loggedin = false; } // Translate Laravel flashed data to existing message arrays if (session()->has('login_error_array')) { $login_error_array = session()->get('login_error_array'); } 

I did some dubious things, always using Laravel auth and LegacyHasher for old passwords, in AuthController:

  /** * Login * * @return \Illuminate\Http\RedirectResponse */ public function postLogin() { // Logic is a bit cleaner to follow if we fail late instead of early if ($this->hasParams(['login_email', 'login_password'])) { // Login using Laravel password $credentials = [ 'email' => strtolower(Input::get('login_email')), 'password' => Input::get('login_password'), 'active' => ['Y', 'B'] ]; // Use the extended user provider to allow using an array of values in the credentials $provider = new ExtendedEloquentUserProvider(new BcryptHasher(), config('auth.model')); Auth::setProvider($provider); if (Auth::attempt($credentials, Input::has('login_remember'))) { Log::info(sprintf('successful login from: %s', $credentials['email'])); return redirect('/'); } // Try with legacy password $provider = new ExtendedEloquentUserProvider(new LegacyHasher(), config('auth.model')); Auth::setProvider($provider); if (Auth::attempt($credentials, Input::has('login_remember'))) { // Save correctly hashed password // TODO: Only add this once this is definitely working ok as it messes up the DB for legacy code //Auth::user()->password = Hash::make(Input::get('login_password')); //Auth::user()->save(); Log::info( sprintf( 'legacy password for login %s, id %d', $credentials['email'], Auth::user()->uid ) ); Log::info(sprintf('successful login from: %s', $credentials['email'])); return redirect('/'); } } Log::warning(sprintf('login failed for: %s', Input::get('login_email'))); // TODO: Use flashed errors for legacy compatibility session()->flash('login_error_array', ['Wrong Username or Password']); return redirect('login.htm')->withInput(); } 

LegacyHasher (yes, that was ...)

 /** * Check the given plain value against a hash. * * @param string $value * @param string $hashedValue * @param array $options * @return bool */ public function check($value, $hashedValue, array $options = array()) { // Unused param $options = []; return md5($value) == $hashedValue; } 

And upload other stuff that is out of frame here. But it is doable, albeit painful. After honestly working on this, all of the old code is removed, and I have a complete, tested Laravel application. He got several hundred TODOs scattered in a liberal, but much more manageable way.

I am happy to help with more detailed information if you decide to go in this direction.

+1
source share

This will not answer your Laravel question directly, but by thinking a little outside the box, you are trying to achieve SSO (single sign) in principle.

For migration, only this can be a redundant solution, but if you plan to migrate more interconnected websites or develop an application, it’s worth considering.

There are three options (as usual):

If we are talking about a third-party library, I can recommend the Auth0 service, which can remove the burden of authentication from you. Depending on the number of users, this may even be a free solution. I recommend this based on my own experience with the service.

More on SSO

Example SSO for autorun

+1
source share

All Articles