Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Migrating anonymous session data and restricting it to authenticated user

Right now the session data for anonymous (non-authenticated) users of my web application is not moved/assigned to the user once they log in or register.

For example: An anonymous user interacts with the application, creates some session data (say products in a shopping cart), then logs in/registers and then logs out, the session data is still accessible and is not moved/made inaccessible to the now unauthenticated user.

I am using file session driver (no database), perhaps someone could provide some example of what needs to be changed (I presume in Session config) in order to make any session data created by an anonymous user become assigned to and only accessible by this user once they authenticate by logging in or registering and only while the user is authenticated.

The requirement for this is because users of the application create unique objects (tied to their user_id) which are only persisted after payment when order processing runs. I store them in session until the user logs-in/registers and goes through with the final order step and only then are they persisted. So I absolutely can't have user specific objects retained in non-authenticated sessions after the user logs out. I could flush the session on logout, but ideally I want to keep them for when the user logs back in.

like image 990
LaserBeak Avatar asked Oct 18 '22 13:10

LaserBeak


1 Answers

The authentication system just uses the session as storage to persist authentication state across requests. However, Laravel's authentication system is not responsible for handling all your session data, it only cares about storing authentication related information, such as user details. If you want to handle additional session data for authenticated users, you need to do that manually.

The logic is simple:

  • If a user does some action like adding something to a shopping cart, the data stays there as the session is bound via cookies to the browser from which the requests are coming from.

  • If a user logs in from that same browser, Laravel's authentication system checks the credentials and if they are correct it stores the necessary information about that user in the same session. The previously stored data about the shopping cart is still there and untouched, so you can use it in the context of the logged in user. If at this point you want to persists the session cart so it's available for the user when he accesses his/hers account in the future, then you need to store the details in the database. Below are a few steps showcasing a way to achieve that:

1. Create an event listener, let's name it SyncShoppingCart, that will listen to the Illuminate\Auth\Events\Login event (the double backslashes in the command \\ are needed to escape a single slash):

php artisan make:listener SyncShoppingCart --event=Illuminate\\Auth\\Events\\Login

2. The previous command created a file in app/Listeners named SyncShoppingCart.php. Now you just need to stores the cart data in the user's in the handle method of that class. The example below assumes you have cart_item table that stores informations about items added to the cart, and you have a CartItem model defined for it. This example is simplified and you will need to modify it to suit your needs, but it's a good starting point for understanding this approach:

public function handle(Login $event)
{
    // Iterate over the session cart items and 
    foreach (session()->get('cart') as $item) {
        $cartItem = new App\CartItem();

        // Set the user ID for the cart item so you know
        // which user added this item to the cart
        $cartItem->user_id = Auth::id();

        // Set the product ID and any other properties
        // you want stored for the cart item
        $cartItem = $item->product_id;
        // ...

        // Save the cart item to the database
        $cartItem->save();
    }

    session()->forget('cart');
}

3. Then register the even listener in the app/Providers/EventServiceProvider.php within the $listen array:

protected $listen = [
    ...
    'Illuminate\Auth\Events\Login' => [
        'App\Listeners\SyncShoppingCart',
    ],
];

Now whenever the user logs in, the App\Listeners\SyncShoppingCart::handle method will be called and will add the items from the session cart to the database. Of course after a user is logged you should store new items added in the database as well, the session alone should be used to store cart info just for guests. On logout you can remove the cart from the session and be done with it, knowing that the cart contents are stored in the database and can be retrieved the next time the user logs in.


You can read more about Authentication Events, Sessions and Events in the Laravel Docs.

like image 54
Bogdan Avatar answered Oct 21 '22 04:10

Bogdan