Following the instructions below, you can configure your own authentication driver, which handles fetching and validating user credentials using an API call:
1. Create your own custom provider in app/Auth/ApiUserProvider.php with the following contents:
namespace App\Auth; use Illuminate\Contracts\Auth\UserProvider; use Illuminate\Contracts\Auth\Authenticatable as UserContract; class ApiUserProvider implements UserProvider { public function retrieveByCredentials(array $credentials) { $user = $this->getUserByUsername($credentials['username']); return $this->getApiUser($user); } public function retrieveById($identifier) { $user = $this->getUserById($identifier); return $this->getApiUser($user); } public function validateCredentials(UserContract $user, array $credentials) { return $user->getAuthPassword() == $credentials['password']; } protected function getApiUser($user) { if ($user !== null) { return new ApiUser($user); } } protected function getUsers() { $ch = curl_init(); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_URL, env('API_HOST') . 'vse/accounts'); $response = curl_exec($ch); $response = json_decode($response, true); curl_close($ch); return $response['data']; } protected function getUserById($id) { $user = []; foreach ($this->getUsers() as $item) { if ($item['account_id'] == $id) { $user = $item; break; } } return $user ?: null; } protected function getUserByUsername($username) { $user = []; foreach ($this->getUsers() as $item) { if ($item['email_address'] == $username) { $user = $item; break; } } return $user ?: null; }
2. Also create a user class that extends the default GenericUser offered by the authentication system in app/Auth/ApiUser.php , with the following contents:
namespace App\Auth; use Illuminate\Auth\GenericUser; use Illuminate\Contracts\Auth\Authenticatable as UserContract; class ApiUser extends GenericUser implements UserContract { public function getAuthIdentifier() { return $this->attributes['account_id']; } }
3. In your app/Providers/AuthServiceProvider.php file upload method, register a new driver provider:
public function boot(GateContract $gate) { $this->registerPolicies($gate);
4. Finally, in your config/auth.php install the driver in your own:
'driver' => 'api',
Now you can do the following in your controller action:
public function postSignIn() { $username = strtolower(Input::get('username')); $password = Input::get('password'); if (Auth::attempt(['username' => $username, 'password' => $password])) { return Redirect::to('/dashboard')->with('success', 'Hi '. $username .'! You have been successfully logged in.'); } else { return Redirect::to('/')->with('error', 'Username/Password Wrong')->withInput(Request::except('password'))->with('username', $username); } }
Calling Auth::user() to get information about the user after a successful login will return an ApiUser instance containing the attributes extracted from the remote API and will look something like this:
ApiUser {#143 βΌ #attributes: array:10 [βΌ "DBA" => "" "account_id" => 111 "account_type" => "admin" "display_name" => "BobJ" "email_address" => " bob@xyzcorp.com " "first_name" => "Bob" "last_name" => "Jones" "password" => "abc" "message" => "Success" "status" => 200 ] }
Since you did not post a sample response that you receive when there is no match in the user email API, I configure the condition in the getUserDetails method to determine if there is a match and return null if the response does not contain the data property or if the data property is empty. You can change this condition to suit your needs.
The above code has been tested with a pushable response that returns the data structure posted in your question and works very well.
As a final note: you should seriously consider modifying the API to handle user authentication sooner rather than later (possibly using an Oauth implementation), because with a password sent (and even more disturbing) like plain text) itβs not what you want to put aside.