Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force Laravel to log in a user using legacy authentication

I am trying to slowly integrate Laravel into a legacy PHP application. One of the tasks is to automatically register a Laravel user session when a user logs in to the old app. I am not trying to implement Laravel authentication, I really just want to piggyback off of existing functionality and force a specific user to be logged in without checking credentials. What I have so far has been cobbled together from other people's hacks 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 this I get a laravel_session cookie that has contents on the client. During the login request after the code above executes, if I dd(Auth::user()) then I get the user I just logged in with. However, on subsequent requests Auth::user() and $this->request->user() both return null in all contexts.

How can I force an active Laravel user session without actually authenticating that will persist across requests?


The ultimate outcome is that Laravel will be running as a 'sub-application' underneath the legacy app while existing features are pulled in one by one so that both will exist for a period of time until all features are implemented in Laravel and it will replace the existing app in full. If it makes more sense to try to take over the legacy authentication with Laravel rather than the other way around I'm open to that, but I'd rather avoid having to change the underlying users table (legacy authentication is happening over LDAP, so there are no passwords locally, there's no remember_token, but that's easy enough to add if I have to). I really am just looking for the shortest path with the least amount of effort/headache.

like image 348
Jeff Lambert Avatar asked Mar 23 '17 16:03

Jeff Lambert


3 Answers

This won't answer your Laravel question directly, but thinking a little bit outside the box, what you are trying to achieve in principle is SSO (single sign on).

For the sake of migration only this might be an overkill solution, but if you're planning to migrate more interconnected websites or develop an app, it's worth considering.

There are three options (as usual):

  • implement your solution
  • use library eg. bshaffer/oauth2-server-php
  • use 3rd party service

If it comes to 3rd party library I can recommend Auth0 service, which can take authentication burden off you. Depending on number of users it might even come as a free solution. I'm recommending this based on my own experience with the service.

More about SSO

Auth0 SSO example

like image 102
lchachurski Avatar answered Oct 09 '22 00:10

lchachurski


This is a little bit tricky because Laravel use encrypted cookies which is handled by EncryptCookies middleware. You can get your code working if you disable it but I wouldn't recommend it.

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

Consider this is called login.php file, which needs $user_id to log the user by id to 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 this is where you can modify the session. And when you return the response, it will be encrypted again and you can then 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();
like image 24
Amr El-Naggar Avatar answered Oct 09 '22 00:10

Amr El-Naggar


You are not calling save() on Session which is why your session does not persist. I modified the last few lines of your code like so:

// 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, only removing the $app['auth']->loginUsingId($user_id); line, to a second file and ran it and the dump shows the same user still logged in. Logging out and removing the line that saves the session will stop this from working. Hopefully this is the solution that you were looking for.

like image 22
Markus Tenghamn Avatar answered Oct 08 '22 23:10

Markus Tenghamn