In my Laravel application I use the auth Middleware to ensure only authenticated users can reach particular routes.
So, in my routes/web.php I have something like this:
Route::group(['middleware' => ['auth', 'user.required.fields']], function () {
}
As you can see I've added an extra Middleware: user.required.fields it looks like this
<?php
namespace App\Http\Middleware;
use Closure;
class CheckUserRequiredFields
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(auth()->user()->has_filled_required_fields){
return $next($request);
}
else{
return redirect()->route('new-user');
}
}
}
The attribute in question looks like this:
/**
* If the user has filled in their role, department and location, allow full access to the intranet
*
* #return void
*/
public function getHasFilledRequiredFieldsAttribute()
{
if ($this->role && $this->department && $this->location) {
return true;
} else {
return false;
}
}
However, this causes an infinite loop.
Is there something in the auth middleware that would cause this? It's almost like the middleware calls itself over and over.
The code will correctly redirect to route('new-user)` but then repeatedly hits the route.
I think you have your route('new-user') defined within this group:
Route::group(['middleware' => ['auth', 'user.required.fields']], function () {
//
}
So, it will be checked by the middleware, that returns the same route again and again, which cause the mentioned loop.
A possible solution is to remove the route from this grop and also not protect it with the CheckUserRequiredFields middleware.
Related
I am trying to send some data from the handle function in a middleware:
<?php
namespace App\Http\Middleware;
class LanguageSwitcher
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (!Session::has('locale'))
{
Session::put('locale',Config::get('app.locale'));
}
App::setLocale(session('locale'));
$locale = session('locale'); // => The data I want to send
return $next($request);
}
}
My web.php:
Route::group(['middleware'=>'language'], function () {
// I want to set the prefix to locale here, but it's undefined
Route::group(['prefix' => $locale], function () {
});
});
I have tried to get the $locale in web.php using Session::get('locale') but I get Null.
So, is there any way to send it from the middleware to the route?
i guest you want to use locale for support multi language. You can do with set locale in middleware and use the locale in your route. Here is my example https://pastebin.pl/view/c5034cb9
in my website i have a fairly complected category which i have to show in every view (in the client side) so i thought i put the code for creating category in a middleware and pass the result to views
so i've created my middleware but i cant figure out how can i pass its data to my view withouth having to do something in the controllers
i've tried these methods in my middleware
<?php
namespace App\Http\Middleware;
use Closure;
class CtegoryMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$request->merge(array("all_categories" => "abc"));
$request['all_categories']= 'abc';
return $next($request);
}
}
route :
Route::group(['middleware' => ['category' ]], function () {
Route::get('/', 'HomeController#index');
});
but in my view when i echo all_categories i get
Undefined variable: all_categories
btw i've checked by echoing something , the middleware gets triggered on the request
I think in your use case, using a globally available view variable should suffice.
<?php
namespace App\Http\Middleware;
use Closure;
class CtegoryMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$request->merge(array("all_categories" => "abc"));
$request['all_categories']= 'abc';
/**
* This variable is available globally on all your views, and sub-views
*/
view()->share('global_all_categories', 'abc');
return $next($request);
}
}
The variable is loaded once (if you do database query, the query will only execute once), and the variable is then stored in the View factory.
I've read about the new policy features in Laravel 5.1.
It looks from the docs that a blacklist approach is chosen by default. E.g. a controller actions is possible until access is checked and denied using a policy.
Is it possible to turn this into a whitelist approach? Thus, every controller action is denied except when it's explicitly granted.
I just found a rather clean way I think, in your routes, you pass a middleware and the policy that needs to be checked.
Example code:
<?php
namespace App\Http\Middleware;
use Closure;
class PolicyMiddleware
{
/**
* Run the request filter.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string $policy The policy that will be checked
* #return mixed
*/
public function handle($request, Closure $next, $policy)
{
if (! $request->user()->can($policy)) {
// Redirect...
}
return $next($request);
}
}
And the corresponding route:
Route::put('post/{id}', ['middleware' => 'policy:policytobechecked', function ($id) {
//
}]);
I created a middleware that checks if the user is authorized to perform an action and added this middleware to the routes that I want to protect like this:
// VerifyPermission middleware
class VerifyPermission {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param $permission
* #return mixed
*/
public function handle($request, Closure $next, $permission)
{
$user = auth()->user();
if (auth()->check() && $user->hasPermission($permission))
{
return $next($request);
}
return redirect('/');
}
}
// Routes
Route::patch('company/{id}', ['as' => 'updateCompany',
'uses' => 'SettingsController#updateCompany',
'middleware' => 'permission:manage_company']
);
My question is, is it necessary to make another check on updateCompany or is the middleware check sufficient?
public function updateCompany()
{
if(Auth::user()->hasPermission('manage_company'))
{
// Updates Company
}
return abort(403, "Unauthorized");
}
No, you should not make another check, the middleware will do it.
In fact handling authentication and permission handling is one of the most frequent uses for middleware
when you specify this:
Route::patch('company/{id}', ['as' => 'updateCompany',
'uses' => 'SettingsController#updateCompany',
'middleware' => 'permission:manage_company']
You're telling laravel that, when it finds a company/{id} route, it should trigger the handle method of the permission:manage_company middleware, before the request is sent to the SettingsController
So, when the request will get to your controller you're sure that it has satisfied all the middleware it went through
I'm new to laravel 5.1.
How can I use middleware parameter to protect my admin routes from users ?
something like this:
Route::group(['middleware' => 'auth:admin'], function()
/* Admin only Routes*/
{
//////
});
I have a field "role" in my "users" table that get two values:
1 for admin
2 for users
In my application, users, have their protected route.
I don't want to use packages.
You can do something like this. Inject the Guard class, then use it to check the user. You dont need to pass the parameter really. Just name your middleware 'admin' or something. The following middleware will check if the current user's role is admin, and if not, redirect to another route. You can do whatever you prefer on failure.
<?php
namespace Portal\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class Admin
{
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($this->auth->user()->role != 'admin') {
return redirect()->route('not-an-admin');
}
return $next($request);
}
}
In case you do want to pass the parameter, you can do this:
public function handle($request, Closure $next, $role)
{
if($this->auth->user()->role != $role) {
return redirect()->route('roles-dont-match');
}
return $next($request);
}