流明的HTTP基本身份验证,不使用数据库
I'm creating a RESTful API using Lumen and would like to add HTTP basic Authentication for security.
On the routes.php
file, it set the auth.basic
middle for every routes:
$app->get('profile', ['middleware' => 'auth.basic', function() {
// logic here
}]);
Now when I access http://example-api.local/profile
I am now prompted with the HTTP basic authentication, which is good. But when I try to login, I get this error message: Fatal error: Class '\App\User' not found in C:\..\vendor\illuminate\auth\EloquentUserProvider.php on line 126
I do not want the validation of users to be done on a database since I will just have one credential so most likely it will just get the username and password on a variable and validate it from there.
Btw, I reference it thru this laracast tutorial. Though it is a Laravel app tutorial, I am implementing it on Lumen app.
I am answering my own question as I was able to make it work but would still like to know more insights from others regarding my solution and the proper laravel way of doing it.
I was able to work on this by creating a custom middleware that does this:
<?php
namespace App\Http\Middleware;
use Closure;
class HttpBasicAuth
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$envs = [
'staging',
'production'
];
if(in_array(app()->environment(), $envs)) {
if($request->getUser() != env('API_USERNAME') || $request->getPassword() != env('API_PASSWORD')) {
$headers = array('WWW-Authenticate' => 'Basic');
return response('Unauthorized', 401, $headers);
}
}
return $next($request);
}
}
If you'll look into the code, it is pretty basic and works well. Though I am wondering if there is a "Laravel" way of doing this as the code above is a plain PHP code that does HTTP basic authentication.
If you'll notice, validation of username and password is hard coded on the .env
file as I do not see the need for database access for validation.
Check your bootstrap/app.php
. Make sure you have registered your auth.basic
middleware, something like this:
$app->routeMiddleware([
'auth.basic' => Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
]);
After that, change your routes:
$app->get('/profile', ['middleware' => 'auth.basic', function() {
// Logic
}]);
EDIT
If you want to use database
instead of eloquent
authentication, you may call:
Auth::setDefaultDriver('database');
Before you attempt to authenticate:
Auth::attempt([
'email' => 'info@foo.bar',
'password' => 'secret',
]);
Edit #2
If you wish to authenticate in hardcode ways, you may define your own driver for AuthManager
class:
Auth::setDefaultDriver('basic');
Auth::extend('basic', function () {
return new App\Auth\Basic();
});
And then below is the basic of App\Auth\Basic
class:
<?php
namespace App\Auth;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Auth\Authenticatable;
class Basic implements UserProvider
{
/**
* Retrieve a user by their unique identifier.
*
* @param mixed $identifier
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
{
}
/**
* Retrieve a user by their unique identifier and "remember me" token.
*
* @param mixed $identifier
* @param string $token
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token)
{
}
/**
* Update the "remember me" token for the given user in storage.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $token
* @return void
*/
public function updateRememberToken(Authenticatable $user, $token)
{
}
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
return new User($credentials);
}
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(Authenticatable $user, array $credentials)
{
$identifier = $user->getAuthIdentifier();
$password = $user->getAuthPassword();
return ($identifier === 'info@foobarinc.com' && $password === 'password');
}
}
Note that validateCredentials
method needs first argument is an implementation of Illuminate\Contracts\Auth\Authenticatable
interface, so you need to create you own User
class:
<?php
namespace App\Auth;
use Illuminate\Support\Fluent;
use Illuminate\Contracts\Auth\Authenticatable;
class User extends Fluent implements Authenticatable
{
/**
* Get the unique identifier for the user.
*
* @return mixed
*/
public function getAuthIdentifier()
{
return $this->email;
}
/**
* Get the password for the user.
*
* @return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the token value for the "remember me" session.
*
* @return string
*/
public function getRememberToken()
{
}
/**
* Set the token value for the "remember me" session.
*
* @param string $value
* @return void
*/
public function setRememberToken($value)
{
}
/**
* Get the column name for the "remember me" token.
*
* @return string
*/
public function getRememberTokenName()
{
}
}
And you may test your own driver via Auth::attempt
method:
Auth::setDefaultDriver('basic');
Auth::extend('basic', function () {
return new App\Auth\Basic();
});
dd(Auth::attempt([
'email' => 'info@foobarinc.com',
'password' => 'password',
])); // return true
First we will extend AuthenticateWithBasicAuth in our middleware.
<?php
namespace App\Http\Middleware;
use \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
class HttpBasicAuth extends AuthenticateWithBasicAuth
{
}
In config/auth.php create custom guard and we will use custom_http_guard with HttpBasicAuth.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'custom_http_guard' => [
'driver' => 'token',
'provider' => 'custom_http_provider',
],
],
We will use Laravel's default 'token' driver.
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'custom_http_provider' => [
'data' => [
'email' => 'info@foo.bar',
'password' => 'secret',
]
],
],
If you can find the way to return data like above.Then you rock and get code following laravel standards.
Hope you got the idea! Looking for final solution. If someone can complete :)
Vaibhav Arora