Search code examples
laravelsessionlaravel-livewirecaslivewire-3

sessions.user_id is null after authenticated and regenerate new session on action


I'm building a system with laravel 11 + livewire 3 and apereo cas for authentication. i'm facing multiple problems due to what i believe is caused by sessions (update: and/or laravel guard) and what i have read and tried to solved it but still no success.

  1. pop-up of "This page has expired. Would you like to refresh?" (at time they're okay, and at other time they'll popup on every action. used to happened only on remote server but now they're happening in my local too)
php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan cache:clear
php artisan optimize
  • empty cache and hard reload
  1. session not persist where after i'm authenticated, a new row in sessions table is added but without sessions.user_id is null. on click/action, a new sessions row is added, this time with user_id. on click/action again its back to the previous session with the null user_id. on click/action again a new sessions row is added, this time with user_id. as it goes on. sometimes a new row of null user_id is added. i'm using staff table instead of users and configured it

web.php

Route::middleware(['cas.auth'])->group(function () {
    // Define routes that require authentication here
    Route::get('/', Home::class);    //redirect here after cas login
    Route::get('staff', Staff::class);
    Route::get('performance', Performance::class);
    Route::get('calendar', Holiday::class);    
});

Route::get('logout', function () {
    Auth::guard('cas')->logout();
    cas()->logout();
});

customcasauth.php (middleware cas.auth)

class CustomCasAuth extends BaseCASAuth
{
    protected $auth;
    protected $cas;

    public function __construct(Guard $auth)
    {
        $this->auth = $auth;
        $this->cas = app('cas');
    }
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($this->cas->checkAuthentication()) {
            $sessionId = session()->getId();
            $session = DB::table('sessions')->where('id', $sessionId)->first();
            dump(Auth::guard('cas')->user());

            if ($session) {
                $sessionLifetime = config('session.lifetime');
                $sessionExpiration = now()->subMinutes($sessionLifetime)->timestamp;

                if (!session('cas_user'))
                    dump('no session');
                elseif (session('cas_user'))
                    dump('have');
                else
                    dump('alou');
                dump(session()->getId());
                if ($session->user_id === null || !session('cas_user')) {
                    dump('in');
                    $staff = Staff::where('staff_short', $this->cas->getUser())->first();
                    if ($staff) {
                        Auth::guard('cas')->login($staff, true);

                        // Store the user credentials in a Laravel managed session
                        session()->put('user_id', $staff->id);
                        session()->save();

                        session()->put('cas_user', $this->cas->user());

                       
                    } else {
                        // Optionally handle the case where no staff record is found
                        abort(403, 'Unauthorized action, please contact administrator to check your existence in the system.');
                    }
                }
                dump('out');
                if (!session('cas_user'))
                    dump('no session');
                elseif (session('cas_user'))
                    dump('have');
                else
                    dump('alou');

                if ($session->last_activity < $sessionExpiration) {
                    // Session has expired
                    Auth::guard('cas')->logout();
                    $this->cas->authenticate();
                }
            } else {
                dump('no session');
                $this->cas->authenticate();
            }
        } else {
            if ($request->ajax() || $request->wantsJson()) {
                return response('Unauthorized.', 401);
            }
            Auth::guard('cas')->logout();
            $this->cas->authenticate();
        }

        return $next($request);
    }
}

auth.php (configure staff model instead of users for auth guard)

 'defaults' => [
        'guard' => env('AUTH_GUARD', 'cas'),
        'passwords' => env('AUTH_PASSWORD_BROKER', 'staff'),
    ],

 'guards' => [
        'cas' => [
            'driver' => 'session', // Custom driver for CAS authentication
            'provider' => 'staff', // Provider for the CAS user
        ],
    ],
  
'providers' => [
        'staff' => [
            'driver' => 'eloquent', // Use Eloquent or a custom provider if needed
            'model' => App\Models\Staff::class,
        ],
    ],

staff.php

use Illuminate\Auth\Authenticatable as AuthAuthenticatable; //use this instead of below because this can be implemented as a trait
// use Illuminate\Foundation\Auth\User as Authenticatable; //not using this since already extend model
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use OwenIt\Auditing\Contracts\Auditable;

class Staff extends Model implements Auditable, AuthenticatableContract
{
    use AuthAuthenticatable;
    use HasFactory;

    protected $username = 'staff_short';

update: i found out that the dump() session in middleware are not the same as the dump() session in my livewire


Solution

  • use check for auth::guard->hasuser, if no user then auth::guard->login, hence no more new session on action