Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I put and retrieve the user information to and from session into a Laravel custom user provider?

I am not so into PHP and Laravel and I have the following problem, I came from Java.

I am following this tutorial to implement a custom user provider:

https://blog.georgebuckingham.com/laravel-52-auth-custom-user-providers-drivers/

I am using Laravel 5.3 version.

I briefly expain what I need: my Laravel application is only a front end application, all the business logic, included the user authentication, is performed by a Java back end application that exposes REST web services.

Performing a call to:

http://localhost:8080/Extranet/login

and passing username and password as basic authentication I obtain a JSON response like this that represent the logged user:

{
  "userName": "Painkiller",
  "email": "[email protected]",
  "enabled": true
}

So, in my Laravel application, I have to perform this call and then parse the previous returned JSON object to generate the authenticated object into the front end application session.

To do this I have implemented the previous tutorial (and it seems to works) implementing this custom user provider class named UserProvider that implements the Laravel IlluminateUserProvider interface:

<?php

namespace App\Authentication;

use Illuminate\Auth\GenericUser;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider as IlluminateUserProvider;
use GuzzleHttp\Client;
use function GuzzleHttp\json_encode;
use function GuzzleHttp\json_decode;
use Illuminate\Support\Facades\Log;

class UserProvider implements IlluminateUserProvider
{
    public function retrieveById($identifier)
    {
        // TODO: Implement retrieveById() method.
        \Log::info('retrieveById START');

        // PERFORM THE CALL TO MY BACK END WB SERVICE AND CREATE A NEW GenericUser USING THESE INFORMATION:

        $attributes = array(
            'id' => 123,
            'username' => '[email protected]',
            'password' => \Hash::make('SuperSecret'),
            'name' => 'Dummy User',
        );

        $user = new GenericUser($attributes);

        return $user;

    }

    public function retrieveByToken($identifier, $token)
    {
        // TODO: Implement retrieveByToken() method.
        \Log::info('retrieveByToken START');
    }

    public function updateRememberToken(Authenticatable $user, $token)
    {
        // TODO: Implement updateRememberToken() method.
        \Log::info('updateRememberToken START');
    }

    public function retrieveByCredentials(array $credentials) {

        // TODO: Implement retrieveByCredentials() method.

        \Log::info('retrieveByCredentials START');
        \Log::info('INSERTED USER CREDENTIAL: '.$credentials['email'] . ' ' .$credentials['password']);

        $client = new Client(); //GuzzleHttp\Client

        $response = $client->get('http://localhost:8080/Extranet/login',
            [
                'auth' => [
                    '[email protected]',
                    'pswd'
                ]
            ]);

        $dettagliLogin = json_decode($response->getBody());

        \Log::info('response: '.(json_encode($dettagliLogin)));

        //$user = new User('Pippo', '[email protected]', true);

        $attributes = array(
            'id' => 123,
            'username' => '[email protected]',
            'password' => \Hash::make('SuperSecret'),
            'name' => 'Dummy User',
        );

        $user = new GenericUser($attributes);

        \Log::info('USER: '.(json_encode($user)));

        return $user;


    }

    public function validateCredentials(Authenticatable $user, array $credentials)
    {
        // TODO: Implement validateCredentials() method.
        \Log::info('validateCredentials START');
        return true;
    }

}

This is only a preliminary test so the returned data are mocked.

It works in this way:

1) When the user insert his credential in the login page (http://localhost:8000/login) it is called the retrieveByCredentials() method:

public function retrieveByCredentials(array $credentials) {

    // TODO: Implement retrieveByCredentials() method.

    \Log::info('retrieveByCredentials START');
    \Log::info('INSERTED USER CREDENTIAL: '.$credentials['email'] . ' ' .$credentials['password']);

    $client = new Client(); //GuzzleHttp\Client

    $response = $client->get('http://localhost:8080/Extranet/login',
        [
            'auth' => [
                '[email protected]',
                'pswd'
            ]
        ]);

    $dettagliLogin = json_decode($response->getBody());

    \Log::info('response: '.(json_encode($dettagliLogin)));

    //$user = new User('Pippo', '[email protected]', true);

    $attributes = array(
        'id' => 123,
        'username' => '[email protected]',
        'password' => \Hash::make('SuperSecret'),
        'name' => 'Dummy User',
    );

    $user = new GenericUser($attributes);

    \Log::info('USER: '.(json_encode($user)));

    return $user;

}

that performs a web service call to obtain the user information related to this user. Then these credential are verified by the validateCredentials() method (at this time it returns true every time). Finnaly it returns a GenericUser objct containing the information of the logged user (at this time are mocked because is a test and I have not yet paresed the JSON reeturned by my web service.

Then, when the user access to the next page (after the success login) it seems to me that is called the retrieveById($identifier) method, this:

public function retrieveById($identifier)
{
    // TODO: Implement retrieveById() method.
    \Log::info('retrieveById START');

    // PERFORM THE CALL TO MY BACK END WB SERVICE AND CREATE A NEW GenericUser USING THESE INFORMATION:

    $attributes = array(
        'id' => 123,
        'username' => '[email protected]',
        'password' => \Hash::make('SuperSecret'),
        'name' => 'Dummy User',
    );

    $user = new GenericUser($attributes);

    return $user;

}

At this time the logic is that it use the id of the previous logged user to perform a call to the back end web service, obtain again these information and create the same GenericUser object that will be returned to the next page that uses it. Now I have mock these userinformation.

Ok, this works but I can't do in this way for security reason.

So my idea is: when I retrieve the user information in the retrieveByCredentials(array $credentials), after have check that are correct, I will put this GenericUser object into session.

Then in the retrieveById() method I will retrieve these information from the session.

Can I do something like this? Could be a smart way? How can I put and retrieve an object\data into and from the session (I am not into PHP and front end).

like image 814
AndreaNobili Avatar asked Jan 28 '17 17:01

AndreaNobili


1 Answers

Yes, you can.

When you log in a user using Laravel's authentication API, it is automatically stored in the application's session. So what you are doing is completely fine.

And you don't need to worry about methods like retrieveByCredentials fireing calls to your REST API when you get the user instance through Auth::user(). Every time this method is called, it checks if there is an user already loged in. If there is, it just returns the user, otherwise, it makes the necessary calls to find that user.

But I would suggest putting those calls to your REST API in another class. The UserProvider has only the responsibility of showing Laravel how to retrieve a user, so it should make use of delegation to call other objects to do the dirty work of finding something somewhere.

You can checkout more about how the session Auth class work in the source of laravel:

https://github.com/laravel/framework/blob/5.4/src/Illuminate/Auth/SessionGuard.php

like image 59
Artenes Nogueira Avatar answered Oct 15 '22 09:10

Artenes Nogueira