I request api to check user , and the backurl will add a query param token like this :
www.test.com?store_id=2&token = 123
I want to show this
www.test.com?store_id=2
I handle it in middleware , I wish there is a mothod to remove token before return $next($request)
but I didn't find the method. And I can't just use some method to delte this params and redirect , it will make a redirect loop.
if there is no better method, maybe I will create a new method in LoginController to remove token and redirect to where the page I from.
You can have some sort of global middleware:
class RedirectIfTokenInRequest {
public function handle($request,$next) {
if ($request->token) {
return redirect()->to(url()->current().'?'.http_build_query($request->except("token")));
}
return $next($request);
}
}
This will just redirect if there's a token parameter there. If you need to store it somehow you can use session(["token" => $request->token]); to store it before your redirect.
Middleware is the best option. You can attach middleware class, to routes, in web or to single method. My middleware proposal:
namespace App\Http\Middleware;
use Closure;
class ClearFromAttributes
{
/**
* Remove some attributes which makes some confusion.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($request->get('unwanted_param')) {
return $this->removeFromQueryAndRedirect($request, 'unwanted_param');
}
if ($request->has('second_unwanted')) {
return $this->removeFromQueryAndRedirect($request, 'second_unwanted');
}
return $next($request);
}
/**
* Remove and make redirection.
*
* #param \Illuminate\Http\Request $request
* #param string $parameter
* #return mixed
*/
public function removeFromQueryAndRedirect($request, string $parameter)
{
$request->query->remove($parameter);
return redirect()->to($request->fullUrlWithQuery([]));
}
}
Of course, I have more complicated conditions in the handle method, in reality.
Usage in controller constructor without touching Kernel file:
$this->middleware(ClearFromAttributes::class)->only('index');
This is a nice option, for single usage.
Laravel 7
You can remove parameter(s) from url by passing null to fullUrlWithQuery function like below:
request()->fullUrlWithQuery(['token ' => null])
Laravel 8 added fullUrlWithoutQuery($keys)
class RemoveParameterFromRequest
{
public function handle(Request $request, Closure $next)
{
if ($request->has('unwanted_parameter')) {
return redirect()->to($request->fullUrlWithoutQuery('unwanted_parameter'));
}
return $next($request);
}
}
Related
I have created a Middleware to check if users with google2fa_enabled = 1 have a google2fa_secret and when they don't, they need to create one.
In the Middleware, I have defined the handle function with an if-statement and when true, it redirects the user to /2fa/create. It didn't work, so I made the if-statement like if(true), but the user is not being redirected. When I replace the return statement after that with return redirect('/2fa/create'), it does redirect, so the middleware is used (also confirmed with the Laravel debugbar)
The Middleware itself:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class checkTwoFactor
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(true){
redirect('/2fa/create');
}
return $next($request);
}
}
And the routes:
Route::get('/', function () {
return view('layouts/master');
})->middleware(['auth', 'check2fa']);
I expect the user to be redirected to /2fa/create at all times (and later on, if user is logged in, has google2fa_enabled = 1 & google2fa_secret == "")
Oops, I found the mistake already.
I need a return statement in that if-statement to work, so redirect() had to be return redirect()
I wrote a very simple middleware, like this:
class CheckToken
{
private $token='xxx';
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (! $request->tokenz == $this->token) {
return response('Unauthorized.', 401);
}
return $next($request);
}
}
Then I register it trough kernel.php, like this:
protected $routeMiddleware = [
.....
'CheckToken' => \App\Http\Middleware\CheckToken::class,
];
then Ive a very simple function in a controller guarded by this controller:
public function __construct()
{
$this->middleware('CheckToken');
}
public function push()
{
return view('home');
}
Now starts what is not clear to me:
how can i "protect" my page using this simple method?
I've tried to put this tag on the header of page but it seems to not works, maybe im in the wrong path:
<meta name="tokenz" content="xxx">
I put it even in the body but no results.
what ive misunderstood?
I believe you need to add the middleware call to the actual route:
use App\Http\Middleware\CheckAge;
Route::get('admin/profile', function () {
//
})->middleware(CheckAge::class);
This was extracted from the Laravel 5.7 documentation: Middleware - Assigning Middleware to Routes
sorry i can't create a comment. but just want to help.
does $request passed a tokenz?
you can use ?tokenz=blablabla
or you can change your method to get the tokenz
I have problem that using multiple parameters in my Route::middleware isn't working for me. I am trying to assign a specific route only accessible for a superuser and admin role.
When I just use:
role:superuser
it works fine, but when I add a second parameter like:
role:superuser,admin
it fails when I assign myself the admin role but still works for the superuser role.
I am confused so any help would be appreciated!
Here is my RoleMiddleware:
namespace App\Http\Middleware;
use Closure;
class RoleMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string $roles
* #return mixed
*/
public function handle($request, Closure $next, ...$roles)
{
$user = $request->user();
if ($user && $user->isSuperuser($roles)) {
return $next($request);
}
return redirect('/home')->withError('U heeft niet de juiste rechten!');
}
}
Here is my isSuperuser method in my User model:
public function isSuperuser(...$roles)
{
if ($roles) {
return $this->roles == $roles;
}
return $this->roles;
}
Last but not least my routes/web code for the middleware:
Route::get('/users', 'UsersController#index')->middleware(['role:superuser,admin']);
Btw: the method is called 'isSuperuser' but that's just a name. It also has to accept the admin role at some point.
use | instead of , like this:
Route::get('/users', 'UsersController#index')->middleware(['role:superuser|admin']);
Generally speaking this should be a rather simple problem. IT should be very similar to the following question on Stack Overflow
But seeing as it has been two years, maybe some of the syntax has changed.
All I want to do is pass a variable from the middleware to the controller, so I'm not duplicating mysql queries.
Here is my middleware:
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$id = $request->user()->id;
$rr = $request->user()->isSuperAdmin();
if ($request->user()->isSuperAdmin()) {
$request->merge(['group' => 123]);
return $next($request);
}
echo "not admin";
}
}
So the middleware works fine and if I DD($request) on the middleware I see my group => 123 on the page. (Right now it's 123 for the sake of simplicity.)
So I want to pass it to my AdminController:
<?php
namespace SleepingOwl\Admin\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use SleepingOwl\Admin\Form\FormElements;
use SleepingOwl\Admin\Form\Columns\Column;
use SleepingOwl\Admin\Display\DisplayTable;
use Illuminate\Contracts\Support\Renderable;
use SleepingOwl\Admin\Display\DisplayTabbed;
use Illuminate\Validation\ValidationException;
use SleepingOwl\Admin\Contracts\AdminInterface;
use SleepingOwl\Admin\Model\ModelConfiguration;
use Illuminate\Contracts\Foundation\Application;
use SleepingOwl\Admin\Contracts\Form\FormInterface;
use SleepingOwl\Admin\Contracts\ModelConfigurationInterface;
use SleepingOwl\Admin\Contracts\Display\ColumnEditableInterface;
class AdminController extends Controller
{
/**
* #var \DaveJamesMiller\Breadcrumbs\Manager
*/
protected $breadcrumbs;
/**
* #var AdminInterface
*/
protected $admin;
/**
* #var
*/
private $parentBreadcrumb = 'home';
/**
* #var Application
*/
public $app;
/**
* AdminController constructor.
*
* #param Request $request
* #param AdminInterface $admin
* #param Application $application
*/
public function __construct(Request $request, AdminInterface $admin, Application $application)
{
$this->middleware('CheckRole');
So as you can see I call the middleware on this constructor. After calling it I should be able do something like:
$request->get('group'); or $request->group;
After trying for quite a while nothing seems to be working and I keep getting a null value. Fundamentally, this shouldn't be terribly difficult, but I seem to have my syntax off or not using the right name spaces?
Instead of this code line:
$request->merge(['group' => 123]);
You can try:
$request->request->add(['group' => 123]);
What this code line will do is if a parameter named group exists in the $request it will overwrite with the new value, otherwise it will add a new parameter group to the $request
In your controller, you can get the value of group parameter as:
$group = $request->group; OR $group = $request->input('group');
Thanks to the joint help of #Rahul-Gupta and #shock_gone_wild. It was a joint effort I guess.
The first issue is that I'm using sleepingOwl laravel boilerplate. Probably not the best idea for someone new to Laravel. (not new to MVC / PHP).
Based on #shock_gone_wild comment, decide move my test over to a simple controller, and not the sleeping owl nonsense. (they have a lot of code.) Anyways, I believe that helped. I did leave the middleware in the constructor because I didn't apply the middleware to the routes.
Then I followed #Rahul-Gupta syntax.
So here is final result, hopefully this will save someone sometime someday...
namespace App\Http\Middleware;
use Closure;
class CheckRole {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next) {
if ($request->user()->isSuperAdmin()) {
$request->request->add(['group' => 123]);
return $next($request);
} else {
echo "not admin";
}
}
}
Then here is the simple controller.
use Illuminate\Http\Request;
use App\task;
use App\User;
use App\HasRoles;
class TaskController extends Controller {
public function __construct() {
// constructor code...
$this->middleware('auth');
$this->middleware('CheckRole');
}
public function index(Request $request) {
$group = $request->input('group');
echo "---->" . $group;
$tasks = Task::all();
return view('test_task', compact('tasks'));
}
}
I have a middleware like this:
<?php
namespace App\Http\Middleware;
use App\Contracts\PermissionsHandlerInterface;
use Closure;
class PermissionsHanlderMiddleware {
public $permissionsHandler;
function __construct(PermissionsHandlerInterface $permissionsHandler) {
$this -> permissionsHandler = $permissionsHandler;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next) {
$routeAction = $request->route()->getActionName();
/*
do some operations
*/
return $next($request);
}
}
but $request->route() always returns null, I think its because the router hasn't been dispatched with the request.
Note: I added my middleware to Kernal.php global middlewares to run before each request as the following
protected $middleware = [
.
.
.
'App\Http\Middleware\PermissionsHanlderMiddleware',
];
I want to get route action name before the execution of $next($request) to do some permission operations. How can i do this ?
You cannot get the route action name if the router has not yet been dispatched. The router class has not yet done its stuff - so you cannot do $router->request() - it will just be null.
If it runs as routeMiddleware as $routeMiddleware - then you can just do $router->request()
You can get the URI string in the middleware before the router has run - and do some logic there if you like: $request->segments(). i.e. that way you can see if the URI segment matches a specific route and run some code.
Edit:
One way I can quickly think of is just wrap all your routes in a group like this:
$router->group(['middleware' => 'permissionsHandler'], function() use ($router) {
// Have every single route here
});
This is the solution I did in my project:
...
public function handle($request, Closure $next) {
DB::beginTransaction();
$nextRequest = $next($request); //The router will be dispatched here, but it will reach to controller's method sometimes, so that we have to use DB transaction.
$routeName = $request->route()->getRouteName();
if ($checkPassed) {
DB::commit();
return $nextRequest;
} else {
DB::rollback();
}
}
This is also fine.
$request->path(); // path
$request->route()->getName()//name of the route