Reputation: 525
I want to create authentication mechanism without need for database where only one person (admin) who knows right username and password (which I would hardcode) would be able to login. I still want to use Auth::attempt(), Auth::check() and other functions.
I found out that I could create my own User driver, but it seems to me that there should be something simpler.
Maybe it is not very nice solution, but I want as simple as possible website.
Upvotes: 4
Views: 1947
Reputation: 1233
The accepted answer did not work for me. Every time I logged in, the login was successful but when on the /home
page, I was redirected to the login page again.
I found out that this was due to the user not being stored in the session as authenticated user. To fix this, I had to implement the getAuthIdentifier
method in the User
model class and also implement the retrieveById
method .
I've also adjusted my solution to support multiple hard coded users (it presumes, that the email is unique, so we can also use it as id for the user):
1. In app/config/auth.php
:
'providers' => [
'users' => [
'driver' => 'array',
],
],
'credentials' => [
'[email protected]' => 'passA',
'[email protected]' => 'passB',
]
2. The UserProvider
:
use \Illuminate\Auth\GenericUser;
use \Illuminate\Contracts\Auth\UserProvider;
use \Illuminate\Contracts\Auth\Authenticatable;
class ArrayUserProvider implements UserProvider
{
private $credential_store;
public function __construct(array $credentials_array)
{
$this->credential_store = $credentials_array;
}
// IMPORTANT: Also implement this method!
public function retrieveById($identifier) {
$username = $identifier;
$password = $this->credential_store[$username];
return new User([
'email' => $username,
'password' => $password,
]);
}
public function retrieveByToken($identifier, $token) { }
public function updateRememberToken(Authenticatable $user, $token) { }
public function retrieveByCredentials(array $credentials)
{
$username = $credentials['email'];
// Check if user even exists
if (!isset($this->credential_store[$username])) {
return null;
}
$password = $this->credential_store[$username];
return new GenericUser([
'email' => $username,
'password' => $password,
'id' => null,
]);
}
public function validateCredentials(Authenticatable $user, array $credentials)
{
return $credentials['email'] == $user->email && $credentials['password'] == $user->getAuthPassword();
}
}
3. And in app/Providers/AuthServiceProvider
:
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider
{
...
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
Auth::provider('array', function($app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new ArrayUserProvider($app['config']['auth.credentials']);
});
}
}
4. In User.php (model):
class User extends Authenticatable
{
...
public function getAuthIdentifier()
{
return $this->email;
}
}
For everyone who is interested, why there need to be the above stated additions:
When you login, the method login
in Illuminate\Auth\SessionGuard
is called. In this method you will find, that the identifier of the user is stored in the session with $this->updateSession($user->getAuthIdentifier())
. Therefore we need to implement this method in our user model.
When you add $this->middleware('auth')
in your controller, then the method authenticate()
in Illuminate\Auth\Middleware\Authenticate
is called. This again calls $this->auth->guard($guard)->check()
to check, whether a user is authenticated. The check()
method only tests, that there exists a user in the session (see Illuminate\Auth\GuardHelpers
). It does this by calling the user()
method of the guard, which in this case is again SessionGuard
. In the user()
method, the user is retrieved by taking the id stored in the session and calling retrieveById
to get the user.
Upvotes: 0
Reputation: 44526
It may only seem there should be something simpler, but in fact that's as simple as you can get if you want to extend the authentication system. All the methods you're using through the Auth
facade (like attempt
, check
, etc.), are implemented within the Illuminate\Auth\Guard
class. This class needs a UserProviderInterface
implementation to be injected into the constructor in order to work. Which means that in order to use the Auth
facade you either need to use the already implemented DatabaseUserProvider
or EloquentUserProvider
, or implement your own provider that handles the simple login you want.
Although the article you linked to may look lengthy, to achieve what you need you might get away with much less code in the provider than you might think. Here's what I think is what you need:
1. In your app/config/auth.php
change the driver to simple
and append the desired login credentials:
'driver' => 'simple',
'credentials' => array(
'email' => '[email protected]',
'password' => 'yourpassword'
)
2. Create a file in your app
directory called SimpleUserProvider.php
that has this code:
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\GenericUser;
use Illuminate\Auth\UserProviderInterface;
class SimpleUserProvider implements UserProviderInterface {
protected $user;
public function __construct(array $credentials)
{
$this->user = new GenericUser(array_merge($credentials, array('id' => null)));
}
// If you only need to login via credentials the following 3 methods
// don't need to be implemented, they just need to be defined
public function retrieveById($identifier) { }
public function retrieveByToken($identifier, $token) { }
public function updateRememberToken(UserInterface $user, $token) { }
public function retrieveByCredentials(array $credentials)
{
return $this->user;
}
public function validateCredentials(UserInterface $user, array $credentials)
{
return $credentials['email'] == $user->email && $credentials['password'] == $user->password;
}
}
3. Lastly you'll need to register the new provider with the authentication system. You can append this to the app/start/global.php
file:
Auth::extend('simple', function($app)
{
return new SimpleUserProvider($app['config']['auth.credentials']);
});
This should give you a simple (no database) user authentication while still being able to use Laravel's facades.
Upvotes: 5