WitHeld WitHeld - 4 months ago 49
PHP Question

How to set up Laravel 5.2 to connect to API

I have a backend C++ application that receives JSON requests using a standard TCP connection. This application manages all the business logic (user authentication, transaction processing, data requests and validation).

How do I need to setup Laravel 5.2 to connect to this server for user authentication and also transaction processing? I do not need any database on the Laravel side as all the data will be accessed through the C++ application.

As a bonus, I would also like to incorporate JWT for the user authentication part if that will be possible.

The code below is the way I currently connect to the application server using standard PHP. I want the same functionality but in a more Laravel way.

class tcp_client
{
private $sock;

function __construct()
{
// create the socket
$this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!is_resource($this->sock))
{
// throw exception
}

// set socket options
$this->set_options();
}

function connect($host, $port)
{
$timeout = 3;
$startTime = time();
while (!socket_connect($this->sock, $host, $port))
{
if ((time() - $startTime ) >= $timeout)
{
// throw exception
}
sleep(1);
}
}

private function set_options()
{
if (!socket_set_option($this->sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 5,
'usec' => 0)))
{
// throw exception
}

if (!socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 5,
'usec' => 0)))
{
// throw exception
}
}

public function request($request)
{
// the first 6 characters will indicate the length of the JSON string
$request = str_pad(strlen($request), 6, '0', STR_PAD_LEFT) . $request;

//Send the message to the server
if (!socket_send($this->sock, $request, strlen($request), 0))
{
// throw exception
}

//Now receive header from server
$header = 0;
if (socket_recv($this->sock, $header, 6, MSG_WAITALL) === FALSE)
{
// throw exception
}

//Now receive body from server
$body = "";
if (socket_recv($this->sock, $body, $header, MSG_WAITALL) === FALSE)
{
// throw exception
}

return $body;
}

}

Answer

I have managed to sort this out on my own by mimicking the DatabaseUserProvider.

  1. Create folder App\Blah with sub folders App\Blah\Auth and App\Blah\TCP

  2. Create a new user provider

    > php artisan make:provider App\Blah\Auth\BlahUserProvider
    
  3. Copied the contents of \vendor\laravel\framework\src\Illuminate\Auth\DatabaseUserProvider.php to the new provider (BlahUserProvider.php) and changed the class name back to BlahUserProvider.

  4. Created App\Blah\TCP\TCPClient.php and copied the contents of the class in my question to this file.

  5. Change the namespace and use the TCPClient and stdClass in BlahUserProvider.php

    namespace App\Blah\Auth;
    use App\Blah\TCP\TCPClient;
    use stdClass;
    
  6. Replaced the contents of function retrieveByCredentials in BlahUserProvider with

    public function retrieveByCredentials(array $credentials)
    { 
      $tcp_request = "{\"request\":\"login\","
                   . "\"email\":\"" . $credentials['email'] . "\","
                   . "\"password\":\"" . $credentials['password'] . "\"}";
    
      $tcp_result = json_decode(str_replace("\n","\\n",$this->conn->request($tcp_request)), true);
    
      $user = new stdClass();
      $user->id = $tcp_result['user']['id'];
      $user->name = $tcp_result['user']['name'];
    
      return $this->getGenericUser($user);
    }
    
  7. I also replaced function retrieveById with the same contents as function retrieveByCredentials for now just so the user can log in because I still have to create the request in the C++ application.

  8. Extended the createUserProvider function in \vendor\laravel\framework\src\Illuminate\Auth\CreatesUserProviders.php to include my new driver and also added function createBlahProvider

    public function createUserProvider($provider)
    {
      $config = $this->app['config']['auth.providers.' . $provider];
    
      if (isset($this->customProviderCreators[$config['driver']]))
      {
        return call_user_func(
                $this->customProviderCreators[$config['driver']], $this->app, $config
        );
      }
    
      switch ($config['driver'])
      {
        case 'database':
            return $this->createDatabaseProvider($config);
        case 'eloquent':
            return $this->createEloquentProvider($config);
        case 'blah':
            return $this->createBlahProvider($config);
        default:
            throw new InvalidArgumentException("Authentication user provider [{$config['driver']}] is not defined.");
      }
    }
    
    protected function createBlahProvider($config)
    {
      $connection = new \App\Blah\TCP\TCPClient();
      return new \App\Blah\Auth\BlahUserProvider($connection, $this->app['hash'], $config['model']);
    }
    
  9. Changed the provider in config\auth.php to the blah user provider

    'providers' => [
      'users' => [
        'driver' => 'blah',
        'model' => App\User::class,
    ],
    
Comments