Passing variables into middleware Laravel - laravel

I am using wildcard subdomains and want to pass the $element variable into the middleware whitelabel so I can check the subdomain and respond accordingly.
Route::group(['domain' => '{element}.website.co', 'middleware' => 'whitelabel'], function() {
Route::get('/', 'AuthController#getLogin');
Route::post('/', 'AuthController#postLogin');
});
How would I use the value of element within the middleware?

Firstly, (unless you already have done) you'll need to add the following to your:
Route::pattern('element', '[a-z0-9.]+');
You can add it to the boot() method of your AppServiceProvider.
Then to access it in your middleware you would have something like:
public function handle($request, Closure $next)
{
$domain = $request->route('element');
return $next($request);
}
Hope this helps!

Related

Laravel: Pass Model Binding to Route Middleware

I have routes that I'm grouping by Location. I need to authorize whether the current user can actually access a particular Location.
I'm wrapping routes in:
Route::group(['prefix' => "{location}", 'middleware' => "has-location-access:location"], function() {
...
My middleware handle method is as follows:
public function handle(Request $request, Closure $next, Location $location)
{
$account = Account::find($request->session()->get('account_id'));
$this->authorize('manageLocation', [$account, $location]);
return $next($request);
}
Instead of the model being passed into this method, I get a string of "location"
App\Http\Middleware\AuthorizeLocationAccess::handle(): Argument #3 ($location) must be of type App\Location, string given
How can I simply have it pass the Location $location into the handle method?
Try this:
Location::find($request->route()->location)

Laravel 6 perform role based routing

I have a route group with different routes. I want to have different role levels access without changing the URL of the application.
For example I want to have /admin as the route and then I want to allow or disallow users based on their roles. Basically, I want every user to be able to see the same page but with different menu options(I know how to do this) but also secure the links from direct access.
Is there a nice way to achieve that without the need of using different middlewares seperately on each route? Since there doesn't seem to be a way to retrieve the $request variable inside the web.php file but only inside a controller. I'm using the sentinel package for auth.
Some sample code of my web.php:
Route::group(
['prefix' => 'admin', 'middleware' => 'customer', 'as' => 'admin.'],
function () {
// Ad list
Route::get('getMyAnnonsList', 'Admin\BackEndController#getMyAdList')->name('getMyAdList');
}
);
Great answer by #lagbox. This is what I did in the end. Very elegant.
web.php:
Route::group(['prefix' => 'admin', 'as' => 'admin.'], function () {
Route::middleware('admin:admin,user')->group(function(){
Route::get('getMyAnnonsList', 'Admin\BackEndController#getMyAdList')->name('getMyAdList');
});
});
middleware:
public function handle($request, Closure $next, ...$roles)
{
if (!Sentinel::check())
return redirect('admin/signin')->with('info', 'You must be logged in!');
foreach($roles as $role)
if($role == Sentinel::getUser()->roles[0]->slug)
return $next($request);
return redirect()->back();
}
I had already answered something like this before, should be working the same still.
You can create a middleware that can be applied to your group. In that middleware it is asking the route itself for the specific roles to check.
How to assign two middleware to the same group of routes. Laravel
Example of middleware:
class CheckMiddleware
{
public function handle($request, Closure $next)
{
$roles = $request->route()->getAction('roles', []);
foreach ((array) $roles as $role) {
// if the user has this role, let them pass through
if (...) {
return $next($request);
}
}
// user is not one of the matching 'roles'
return redirect('/');
}
}
Example route definition:
Route::middleware('rolescheck')->group(function () {
Route::get('something', ['uses' => 'SomeController#method', 'roles' => [...]])->name(...);
});
You can apply this arbitrary data at the group level, the individual route level or both, as all routes are individually registered; groups just allow for cascading of configuration.
You could also have this middleware take parameters, and just merge them with the arbitrary roles, then it is a dual purpose middleware:
public function handle($request, $next, ...$roles)
{
$roles = array_merge($roles, $request->route()->getAction('roles', []));
...
}
Route::middleware('rolescheck:admin,staff')->group(...);
You can use Laravel Gate And Policies
You can define the gate inside the App > Providers > AuthServiceProvider
and you can also create policies per CRUD. just see info in php artisan help make:policy. This will create a folder in your app called policies you can define the who can access it.
In your controller you can do is this: (this is a gate middleware)
I define the gate first:
Gate::define('check', function ($user, $request) {
return $user->roles->contains('name', $request) || $user->roles->contains('name', 'root');
});
then I initialise it in the controller
abort_if(Gate::denies('check', 'admin only'), 403);
This will throw 403 error if the user don't have access on that role. It will check if the user has admin only role. If it doesn't have it will throw the error
In your view if you want to disable anchor links you can do like this:
#can('check', 'admin only')
dashboard
#endcan
EDIT:
Controller
public function index() {
abort_if(Gate::denies('check', 'admin only'), 403);
// Your Code...
}

Auth::user() is null in new route

i'm using laravel 6 and have 2 route in my app; index and dashboard.
My routes/web is:
Auth::routes();
Route::middleware(['auth'])->group(function () {
Route::get('/index', 'todoApp\TodoController#index')->name('index');
Route::get('/dashboard', 'todoApp\Dashboard#dashboard')->name('dashboard');
});
i added dashboard route recently.
Auth::user() is null when i dump it in dashboard route but doesn't in index. What's the
Your Controller is instantiated before the middleware stack has ran; this is how Laravel can know what middleware you have set via the constructor. Because of this you will not have access to the authenticated user or sessions at this point. Ex:
public function __construct()
{
$this->user = Auth::user(); // will always be null
}
If you need to assign such a variable or access this type of information you would need to use a controller middleware which will run in the stack after the StartSession middleware:
public function __construct()
{
$this->middleware(function ($request, $next) {
// this is getting executed later after the other middleware has ran
$this->user = Auth::user();
return $next($request);
});
}
When the dashboard method is called, the middleware stack has already passed the Request all the way through to the end of the stack so all the middleware needed for Auth to be functioning and available has already ran at that point which is why you have access to Auth::user() there.
I think that this has something to do with the 'web' middleware. If you take a look into the Kernel.php (In app\Http) you will find the web middleware group.
This will show you that it actually calls a middleware called StartSession. Based on your route file (where web is not included as a middleware) I would think that you don't have a session in your Controller and there for no access to it.
I don't quite understand why this only happens in your /dashboard route, because the issue should also be in your /index route (unless you added the web middleware somewhere in your TodoController).
I think that this should do the trick:
Route::middleware(['web', 'auth'])->group(function () {
Route::get('/index', 'todoApp\TodoController#index')->name('index');
Route::get('/dashboard', 'todoApp\Dashboard#dashboard')->name('dashboard');
});
If you fire php artisan make:auth command.
It's doesn't matter where you define because of it's only define auth route
Route::middleware(['auth'])->group(function () {
Route::get('/index', 'todoApp\TodoController#index')->name('index');
Route::get('/dashboard', 'todoApp\Dashboard#dashboard')->name('dashboard');
});
Auth::routes();

How to use a dynamic variable in Laravel group routes?

for example:
Route::group(['prefix' => '{lang?}'], function () {
//..
});
create a variable in middleware:
public function handle($request, Closure $next){
$lang = session('locale');
App::setLocale($lang);
return $next($request);
});
also tried to get the data in the prefix, but got null
Route::group(['prefix' => config('app.locale')], function () {
//..
});
or
Route::group(['prefix' => session('locale')], function () {
//..
});
change language separate route through session
Route::get('setlocale/{locale}', function ($locale) {
session(['locale' => $locale]);
return redirect()->back();
})->name('setlocale');
Thank you in advance for your help.
You don't need to group your routes under a lang route, you can create your own middleware and group your routes under that middleware, and use this code inside of it:
public function handle($request, Closure $next){
$lang = request->get('locale');
$currentLang = App::getLocale();
//If locale exists in the url and it's changed
if($lang && $lang != $currentLang) App::setLocale($lang);
//If locale doesn't exist in the url, fallback to default locale
if(!$lang) App::setLocale('en');
return $next($request);
});
The url should be data/store?locale=en, ur url should always append locale after ? in the url, otherwise, your default locale will be used
EDIT: Since your routes include locale as a part of the url, and not as a request param, then I suggest you use a library to handle this for you, because you will have a lot of stuff to do before you will be able to have a working example: Laravel localization mcmara

Laravel middleware with prefix not working

Currently I am working with a new project with laravel. For this project I need to add prefix for a group of routes and need to add the prefix by using middleware. The middleware is -
public function handle($request, Closure $next)
{
$segments = $request->segments();
if( $request->is('admin/*') ){
return $next($request);
}
array_unshift($segments,'admin');
return redirect()->to(implode('/',$segments));
}
And my routes/web.php file is-
Route::group(['middleware' => 'admin','prefix' => 'admin'],function(){
Route::get('segments',function(){
return request()->segments();
});
});
But unfortunately this is not working for me. The middleware not force redirect me if I don't add admin/ prefix manually. But if I remove 'prefix' => 'admin' from the route group then it works. How can I solve this problem?
Sorry, for my bad English.
This approach will not work for you because you're only applying the middleware to the admin/* routes.
If you want to redirect a user from any not admin/* routes to admin ones, you could do something like this instead. Add this route to the end of the web.php:
Route::get('{param1?}/{param2?}/{param3?}', 'RedirectController#redirectoToAdmin');
Create RedirectController controller and do this:
public function redirectoToAdmin()
{
return redirect('admin/' . request()->path());
}
Also, remove the admin middleware from the route group you've shown.

Resources