I really like working with Laravel. Whenever I need to extend some older project I want to do it in this awesome framework. Some times it is possible sometimes not. I wanted to start one feature in Laravel and gradually transfer all other parts of the old system too.
What to do when you want to share authenticated users?
I figured out two solutions:
- Make Laravel sub directory in existing project. Problem with this may be some dodgy apache config in the old project that would prevent that from working
- The second is to make a sub domain.
This way they could share sessions between themselves.
We need to tell old project to share cookies on all sub domains. Add this on the place you're starting sessions.
session_name('gather-rs');
// set top lvl domain
$domainParts = array_slice(explode('.', $_SERVER['HTTP_HOST']), -2, 2);
$domain = implode('.', $domainParts);
session_set_cookie_params(0, '/', '.'.$domain);
session_start();
Pay attention on session name, it has allowed set of characters to be used in the name. session_start(): The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,'
Also critical thing is to always use same domain for cookies. If you have different sub domains, always use top level domain for cookies to avoid different kind of problems.
When changing these things make sure you clear your browser cookies.
From version 5 Laravel (read more here) is not using PHP sessions. That is actually a good thing. We will NOT change config/session.php
config since we need to start native session and read from global $_SESSION
variable, and these from session.php are only for Laravel session drivers. So Ignore it!
Only thing we need to change is session cookie domain. To do that, open .env
file and add folowing.
(You could do it in session.php
- this is better).
SESSION_DOMAIN=.yourdomain.com
Now let's make a nice guard which will try to pull session data from old system and authenticate the user based on some criteria (usually user id).
Create a custom Laravel guard which will handle legacy user sessions.
<?php
namespace App;
use Illuminate\Auth\SessionGuard;
class LegacySessionGuard extends SessionGuard
{
public function user()
{
if ($this->loggedOut) {
return;
}
if (!is_null($this->user)) {
return $this->user;
}
$id = array_get($this->getSessionData(), 'user_info.id');
$user = null;
if (!is_null($id)) {
$user = $this->provider->retrieveById($id);
}
return $this->user = $user;
}
protected function getSessionData()
{
// Here we will start native PHP Session with
// same name that we set in our old project
if (session_status() == PHP_SESSION_NONE) {
session_name('gather-rs');
$domainParts = array_slice(explode('.', $this->getRequest()->getHost()), -2, 2);
$domain = implode('.', $domainParts);
session_set_cookie_params(0, '/', '.'.$domain);
session_start();
}
return $_SESSION;
}
}
Next we need to register (extend) it somehow. We can do that in the app/Providers/AuthServiceProvider.php
.
Change boot
method to this:
public function boot(GateContract $gate, AuthManager $auth)
{
$this->registerPolicies($gate);
$auth->extend('legacy', function ($app) use ($auth){
$config = $app['config']['auth.guards.legacy'];
$provider = $auth->createUserProvider($config['provider']);
return new LegacySessionGuard('legacy', $provider, $this->app['session.store']);
});
}
Here we are extending auth manager with new guard, but if you try to use it you would see something like Auth guard [legacy] is not defined.
That is because you must define it in the config/auth.php
(laravel something internally).
'guards' => [
// ...
'legacy' => [
'driver' => 'legacy',
'provider' => 'users'
]
],
Now you can use newly created guard. How you want to use it - it depends. You could immediately "transfer" legacy user session to the new app, or keep using old one. If you decide for a second one you can set default guard to be legacy
in config/auth.php
. I chose first option - to immediatelly transfer user to a new session handled by default web
guard.
My Authenticate
middleware looks like this:
public function handle($request, Closure $next, $guard = null)
{
// If user is logged on legacy system but not on
// the new one
$legacyGuard = Auth::guard('legacy');
if (Auth::guard($guard)->guest() && $legacyGuard->check()){
Auth::guard($guard)->login($legacyGuard->user());
}
if (Auth::guard($guard)->guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
}
return redirect()->guest('login');
}
return $next($request);
}
These are more of a notes then a tutorial. Also I'm using same users table in both systems, old and new one, so that makes things easier I guess.