Laravel 5.4 Basic Authentication without a database - php

Problem: I need to implement a basic authentication on my API created with Laravel 5.4. Since we need to implement it without a database (just getting credentials from config()), I tried to create a registered middleware like the following one:
<?php
namespace App\Http\Middleware;
class AuthenticateOnceWithBasicAuth
{
public function handle($request, $next)
{
if($request->getUser() != conf('auth.credentials.user') && $request->getPassword() != conf('auth.credentials.pass')) {
$headers = array('WWW-Authenticate' => 'Basic');
return response('Unauthorized', 401, $headers);
}
return $next($request);
}
}
It works, but this way I can only have one credentials for the whole API.
I've tried to create more then one credentials in the config, saving user and password from request, but this way, it works like basic auth is disabled.
Question: is there any way to achieve this? How can I have multiple credentials in my config file, without using a database?

You can save your authorized usernames and password in your config file as a Collection.
config/myconfig.php
return [
'authorized_identities' => collect([
['user1','password1'],
['user2','password2'],
...
]),
];
and then in your middleware
if(config('myconfig.authorized_identites')->contains([$request->getUser(),$request->getPassword()]))

You can have an array of credentials and try to match the input with anyone of them and validate. To be honest you could easily implement this with a sqlite database. It requires minimalistic setup and you can get started and use it within 5 mins.

Related

Laravel REST API - infinite loop

I am building a REST user-microservice using Laravel 5.5 + Passport.
I am using the standard Passport::routes(), but I have had to modify the Auth::routes in order to make them return JSON responses, and to make them work with Passport.
I have added the following lines to my routes/web.php file:
Route::group(['middleware' => 'auth:api'], function () {
$this->post('logout', 'Auth\LoginController#logout')->name('logout');
});
This allows me to POST https://myapi/logout
If I make the call with the header "Authorization => Bearer TOKEN", I get a successful logout response.
If I provide no header at all, I get a "not authenticated" message (which is good)
However, if I provide the header with a revoked token, I get a recursive deadloop of the function: Illuminate\Auth\RequestGuard->user() (it keeps calling itself recursively until stack-overflow)
This is all done in the auth:api middleware, my logout code is not reached, but my LoginController constructor is called. Constructor code:
public function __construct(Application $app)
{
$this->apiConsumer = $app->make('apiconsumer');
$this->middleware('guest')
->except('logout');
}
I'm struggling to understand if it's my code causing this issue, or some combination of Laravel + passport + auth.
My first thought was that the auth:api middleware fails to authenticate the user, and as a result redirects the user to /home, where for some reason it's triggered again, recursively. But if that was the case, why would it work correctly with no header?
My current thinking is that the token in question does exist in the database, but Laravel is failing to figure out that it's revoked.
Any suggestions appreciated,
I found an answer (if not the answer) after a lot of research. It appears this is a Laravel bug (https://github.com/laravel/passport/issues/440). The solution is to add OAuthServerException to the $dontReport array in app/Exceptions/Handler.php:
class Handler extends ExceptionHandler
{
protected $dontReport = [
...
\League\OAuth2\Server\Exception\OAuthServerException::class,
];
}
This will avoid trying to log user information, thereby avoid the deadloop.
I have faced this in localhost. in my case, I have used xampp server and facing this issue
after creating a virtual host like "testlarave.test" then solve the error

modify Laravel Auth registration page

I am trying to modify the Laravel Auth registration system in that I'd like to require that a token parameter be provided in order for the user to be able to access the registration page (ie http://website.dev/register/{tokenhere}). Below is the pertinent code:
From my routes\web.php file:
Route::get('/register/{token}', function() {
//
})->middleware('token');
From my \App\Http\Middleware\CheckToken.php file:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckToken
{
public function handle($request, Closure $next)
{
if($request->token != 'test') { #just hard coding something here for testing purposes
return redirect('home');
}
return $next($request);
}
}
I also added 'token' => \App\Http\Middleware\CheckToken::class to the $routeMiddleware array in \App\Http\Kernel.php
However, I go to http://website.dev/register and I'm able to access the page, despite not providing a token parameter. I can also see that if I provide the 'test' parameter that the middleware is looking for (http://website.dev/register/test), I get a blank page.
Hoping someone can point me in the right direction. I'm quite new to MVC and Laravel. Thanks for your time!
You can just create custom route, like /register/{token} and handle this token in the controller. Maybe even set in middleware group if you want.

Laravel Auth external data for login and register

I am using the Laravel 5.2 Auth system coming up with this command :
php artisan make:auth
Although this works totally fine as is, my goal is to use an external API to perform login, registering and changing password while still being able to use the core function of the Auth class.
So taking the login for example, I want to use something like
function login(ApiController $api) {
// This function return data or error code and message in JSON
$login = $api->login([ $credentials['email'], $credentials['password']]);
if($login->success)
// login successfully like normal Auth would do
else
// redirect to main page with $login->message
}
By the way, I want to pass fields coming up from $login to the Auth class, like we can actually do Auth::user()->email giving us the email, I'd want to set value like "database field" but with my API JSON fields behind
I looked on the Internet and found something to do inside AuthController and something related to ServiceProvider, but I don't know how to follow my exact needs
Adding a custom user provider would help in this case. There is no need to play with AuthController here. Check this Laravel Docs page.
You will need to create a new User Provider which implements Illuminate\Contracts\Auth\UserProvider, specify it in AuthServiceProvider and update your auth config file accordingly.
Here are the links to the framework's default User Providers for reference :
1) DatabaseUserProvider
2) EloquentUserProvider
I ended up coding my own Auth system...
Using session() and Input()

How can we redirect a page to another if a session is not found using route in Laravel 5.3

I am using a session separately other than the default authentication sessions. If an user try to access my secured page, he should have the session set. If anyone without that session try to access means, they will be redirected to error page. I am using Laravel 5.3
The user can view the below two pages only if the session variable named 'secured_user' is set. Otherwise they will be redirect to the error page
Route::get('/secured-page1', 'ValidationController#CheckSecuredLogin_1');
Route::get('/secured-page2', 'ValidationController#CheckSecuredLogin_2');
The best option would be a policy.
You can create certain constrains and couple it with your models. Policies are especially suitable for changing your logic later on.
See here: Create Policy
Within you PagesPolicy, you can add this function:
public function before(User $user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
public function seeSecurePage(User $user)
{
// Your custom Code and session handling
if(session("secured_user")) return true;
return false;
}
and in your controller.
$user->can("seeSecurePage","Pages");
If "can" fails, it will automatically redirect to error 403.
P.S.: Another possibility are Gates
You should use Laravel Middlewares to achieve this, I think middlewares are made for the work you need:
First create a new middleware by running the artisan command:
php artisan make:middleware CheckSesison
Then the CheckSession would look like this:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckSession
{
public function handle($request, Closure $next)
{
if ($session_value != 'YOUR_DESIRED_VALUE') {
return redirect('home');
}
return $next($request);
}
}
Now in your routes file you can use laravel's route middleware() method to implement it like this:
Route::get('/secured-page1', 'ValidationController#CheckSecuredLogin_1')
->middleware(CheckSession::class);
Hope this helps!
In addition to the awnser above, you could also use middleware that's used on the routes and even group them if required. It is a simple, quick and clean solution. Inside the middelware you simple check if the session you require is there and depending on the result you take any action necessary.
Laravel middleware docs

Laravel 5 Basic Auth custom error

In Laravel 5, if basic auth fails for a user then the default message that is returned is an "Invalid Credentials" error string. I am trying to return a custom JSON error when this situation occurs.
I can edit the returned response in vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php
however I have not seen where you can change the behavior of this message outside of the vendor directory. Is there a way?
Looks like there were some ways to do this through Laravel 4: Laravel 4 Basic Auth custom error
Figured it out, looks like I had to create custom middleware to handle this.
Note that this solution didn't work when calling my API from my browser, only when calling it from a tool like Postman. For some reason when calling it from my browser I always got the error before seeing the basic auth prompt.
In my controller I changed the middleware to my newly created one:
$this->middleware('custom');
In Kernel I added the location for it:
protected $routeMiddleware = [
'auth.basic.once' => \App\Http\Middleware\Custom::class,
]
Then I created the middleware. I used Stateless Basic Auth since I'm creating an API:
<?php
namespace App\Http\Middleware;
use Auth;
use Closure;
use Illuminate\Http\Request as HttpRequest;
use App\Entities\CustomErrorResponse
class Custom
{
public function __construct(CustomErrorResponse $customErrorResponse) {
$this->customErrorResponse = $customErrorResponse
}
public function handle($request, Closure $next)
{
$response = Auth::onceBasic();
if (!$response) {
return $next($request);
}
return $this->customErrorResponse->send();
}
}

Categories