How to use Laravel Package LandLord - php

Im still fairly new to Laravel and have worked through some of the fundamental laracasts. Now I'm starting my first laravel project but I am stuck on how to use my first package "Landlord". Basically I need a setup for Multi-Tenants in my application. I have a company table and a user table, the user table has a company_id column. When a company registers it successfully creates the company and attaches the company_id to the user.
I assume Landlord is the best way to implement a multi-tenant application so I worked through the installation instructions and now I have it included in my app.
However the first line in the USAGE section says:
IMPORTANT NOTE: Landlord is stateless. This means that when you call addTenant(), it will only scope the current request.
Make sure that you are adding your tenants in such a way that it
happens on every request, and before you need Models scoped, like in a
middleware or as part of a stateless authentication method like OAuth.
And it looks like I need to attach a the Landlord::addTenant('tenant_id', 1); facade.
This may be a pretty simple answer I am overlooking but where is the best place to to use addTenant and do I have to redeclare it with every controller or model? Should I attach it when the user signs in, use it in my routes or use as a middleware? If it is a middleware is the following correct in order to pull the company_id from the current user and use it with addTenant?
Middleware:
public function handle($request, Closure $next){
$tenantId = Auth::user()->tenant_id;
Landlord::addTenant('tenant_id', $tenantId);
return $next($request);
}
UPDATE
Here is my middleware (MultiTenant.php)
<?php
namespace App\Http\Middleware;
use Closure;
use App\User;
use Illuminate\Support\Facades\Auth;
class MultiTenant
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::check()) {
$tenantId = Auth::user()->company_id;
Landlord::addTenant('company_id', $tenantId); // Different column name, but same concept
}
return $next($request);
}
}
My routes/web.php
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| This file is where you may define all of the routes that are handled
| by your application. Just tell Laravel the URIs it should respond
| to using a Closure or controller method. Build something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::group(['middleware' => ['multitenant']], function () {
Route::get('/home', 'HomeController#index');
//Clients
Route::resource('clients', 'ClientController');
});
My Client.php Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use HipsterJazzbo\Landlord\BelongsToTenants;
class Client extends Model
{
use BelongsToTenants;
//
protected $fillable = [
'organization',
];
}
https://github.com/HipsterJazzbo/Landlord#user-content-usage

While just one option, I also went the middleware route. I saw it as an easy way to implement it.
I added the middleware to my routes/web.php file:
Route::group(['middleware' => ['landlord']], function () {
// Your routes
});
And my landlord middleware looks like this:
public function handle($request, Closure $next)
{
if (Auth::check()) {
$tenantId = Auth::user()->company_id;
Landlord::addTenant('company_id', $tenantId); // Different column name, but same concept
}
return $next($request);
}
Then I just add the trait to the models that I want scoped:
use HipsterJazzbo\Landlord\BelongsToTenant;
class User extends Authenticatable
{
use BelongsToTenant;
}
Update
Also, make sure in your config/app.php file you have added landlord to the providers array:
'providers' => [
// ...
HipsterJazzbo\Landlord\LandlordServiceProvider::class
// ...
],
And to the aliases array:
'aliases' => [
// ...
'Landlord' => HipsterJazzbo\Landlord\Facades\Landlord::class,
// ...
],
Then finally composer dump-autoload when completed to refresh the autoloading.

Related

Laravel, first user is only user

I am building a Laravel site for personal use and I would like to make the first user to register on the site be the only user. So with a fresh Laravel install with the ui installed, migration sorted and no users registered, I would like the register route to be reachable. But if there is a registered user, block the register route and only allow the login route to be reachable.
I could do something like this in the web.php
Route:get('/register', function () {...})->auth();
But I would have to do that after I first create a user. I'd rather do it in a more controllable fashion.
Edit
I don't doubt that #yves-kipondo's answer is the more correct option if I were to create this for someone else.
The solution I went with is a simple one. In my register controller I just add a check in the constructor, if there already is a user return a 404.
public function __construct() {
if (!User::all()) {
$this->middleware('guest');
} else {
abort(404);
}
}
You can create a Middleware which will be register on the register route
<?php
namespace App\Http\Middleware;
use Closure;
class RegisterOnce
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (User::count() !== 0) {
// you can redirect wherever you want
return redirect('home');
}
return $next($request);
}
}
After that you can register the middleware in the app/Http/Kernel.php by adding this line after all registered routes middleware like this
protected $routeMiddleware = [
\\ ... previous registered middleware
'once' => App\Http\Middleware\RegisterOnce::class,
];
and you can customize the register route like this in the routes/web.php file
which wille replace the default set by Auth::routes();
Route::get('register', [App\Controllers\Auth\RegisterController::class, 'showRegistrationForm'])
->name('register')
->middleware('once');

How can I use HipsterJazzbo/Landlord package -single database multi-tenancy- in Laravel 5.2?

I am using https://github.com/HipsterJazzbo/Landlord single database multi-tenancy solution for Laravel 5.2+. I have a companies table, and all other tables have a company_id column.
I'm not sure how to implement the call Landlord::addTenant($tenantColumn, $tenantId) in a global Middleware, in an auth system or in the constructor of a base controller... I'm confused...
How do I do that?
Is the parameter $tenantColumn equivalent to the company_id column of each of the tables?
Is the parameter $tenantId refers to the id of each company contained in the column company_id?
thank you!
A global middleware is not the good place because you don't have access to the authenticated user. A solution is to create a route middleware, for example:
<?php
namespace App\Http\Middleware;
use Closure;
use HipsterJazzbo\Landlord\Facades\Landlord;
use Illuminate\Support\Facades\Auth;
class LimitToCurrentCompany
{
public function handle($request, Closure $next)
{
if (Auth::check()) {
$tenant = Auth::user()->currentCompany;
Landlord::addTenant($tenant);
}
return $next($request);
}
}
add it to $routeMiddleware array in app/Http/Kernel.php:
protected $routeMiddleware = [
[…]
'limitToCurrentCompany' => \App\Http\Middleware\LimitToCurrentCompany::class,
];
Then in your routes file:
Route::group(['middleware' => 'limitToCurrentCompany'], function () {
// your routes
});
And yes, like said in the comment, $tenantColumn is the company_id and $tenantId is the id of the company.

a middleware to be run during every HTTP request to application except one in laravel 5.1

I want to create my app ( I dont want to use laravel default login system)
I want to use a middleware to be run during every HTTP request in my application except one
in laravel 5.1 documention syas I can use Global Middleware but I want to not use middleware for just login page.
what should I do ?
this is my middleware :
<?php
namespace App\Http\Middleware;
use Closure;
class Admin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if( ! session()->has('Login' ) )
{
return redirect('login');
}
return $next($request);
}
}
You can use routes group and assign your middleware to it:
Route::group(['middleware' => 'Admin'], function () {
// All of your routes goes here
});
// Special routes which you dont want going thorugh the this middleware goes here
Don't do anything to your middleware. you have the free to take that route outside the route group. so it becomes a standalone route. Or you can create a new route group and put only that one route in without that middleware. eg.
Route::group(['prefix' => 'v1'], function () {
Route::post('login','AuthenticationController');
});
Route::group(['prefix' => 'v1', 'middleware' => 'web'], function () {
Route::resource('deparments','AuthenticationController');
Route::resource("permission_roles","PermissionRolesController");
});
with this the middleware affect only the second route group
There are a couple of ways to tackle this, one is to address this in your middleware and exclude the route there, and two is to group all the routes you want to have covered by the middleware in your routes.php and then have the ones you want excluded outside of the grouping.
Tackling this in middleware
Just amend the handle function to include an if statement checking the URI requested
public function handle($request, Closure $next)
{
if ($request->is("route/you/want/to/exclude"))
{
return $next($request);
}
if( ! session()->has('Login' ) )
{
return redirect('login');
}
else
{
return redirect('login');
}
}
This method allows you to set the middleware up as global middleware and you can make multiple exclusions by extending the if statement with or $request->is().
Tackling this in routes
//Place all the routes you don't want protected here
Route::group(['middleware' => 'admin'], function () {
//Place all the routes you want protected in here
});

Different users, middleware Laravel 5

I'm trying to use different user levels at my system. I have at data base my users and their levels (master, portais, chaves, etc)
So, what I want is different routes for each user, so each one will access just a part of the system.
I can easily check in each page of the system his AUTH and dont show to him the page if he is logged in a account witch he shouldn't see that page. BUT, there's a easy way to do it with middleware / Routes no?!
I tried something like this on my routes.php:
Route::group(['middleware' => 'Master'], function()
{
Route::any('/vendedor/produtos/removeProduto', 'AjaxController#vendedorRemoveProduto');
Route::any('/vendedor/produtos/editaPrecoProduto', 'AjaxController#editaPrecoProduto');
Route::any('/vendedor/produtos/alterarestadoproduto', 'AjaxController#alterarestadoumproduto');
Route::any('/vendedor/produtos/listaProdutos', 'AjaxController#listaProdutos');
Route::any('/vendedor/produtos/adicionaProdutoCliente', 'AjaxController#adicionaProdutoCliente');
Route::any('/', 'DashboardController#home'); });
Route::group(['middleware' => 'portais'], function()
{
Route::any('/cadastrarobjedu/criartema', 'AjaxController#criartemaobjedu');
Route::any('/cadastrarobjedu/cadastrar', 'AjaxController#cadastraobjedu');
Route::any('/cadastrarobjedu', 'DashboardController#cadastrarobjedu');
Route::any('/listarobjedu', 'DashboardController#listarobjedu');
Route::any('/editarobjeto/{id}', 'DashboardController#editarobjeto');
Route::any('/apagarobjeto/{id}', 'AjaxController#apagarobjeto');
Route::any('/', 'DashboardController#home'); });
But this didn't work, hgive me a error saying the "MASTER" class dosen't exist. I have change anything more?
You need to implement a middleware that would check if current user has given level.
Laravel 5.0
//app/Http/Kernel.php - register middleware classes
protected $routeMiddleware = [
'levelMaster' => 'App\Http\Middleware\LevelMasterMiddleware',
'levelPortais' => 'App\Http\Middleware\LevelPortaisMiddleware'
];
//app/Http/Middleware/LevelMiddleware.php - base middleware class that checks if user has level stored in $level;
namespace App\Http\Middleware;
use Closure;
use App;
use Auth;
abstract class LevelMiddleware
{
protected $level;
public function handle($request, Closure $next)
{
if (Auth::user() && Auth::user()->level !== $this->level) {
return App::abort(Auth::check() ? 403 : 401, Auth::check() ? 'Forbidden' : 'Unauthorized');
}
return $next($request);
}
}
//app/Kernel/Middleware/LevelMasterMiddleware.php - checks if user has level Master
namespace App\Http\Middleware;
class LevelMasterMiddleware extends LevelMiddleware
{
protected $level = 'master';
}
//app/Kernel/Middleware/LevelPortaisMiddleware.php - checks if user has level Portais
namespace App\Http\Middleware;
class LevelPortaisMiddleware extends LevelMiddleware
{
protected $level = 'portais';
}
//config/routes.php - configure routes for different levels
Route::group(['middleware' => 'levelMaster'], function()
{
//here add routes for users with level=master
}
Route::group(['middleware' => 'levelPortais'], function()
{
//here add routes for users with level=portais
}
Laravel 5.1
The latest version of Laravel introduces middleware parameters which lets simplify the above code a bit, as only one middleware class will be needed:
//app/Http/Kernel.php - register middleware class
protected $routeMiddleware = ['level' => 'App\Http\Middleware\LevelMiddleware'];
//app/Http/Middleware/LevelMiddleware.php - check if current user has given level
namespace App\Http\Middleware;
use Closure;
use App;
use Auth;
class LevelMiddleware
{
public function handle($request, Closure $next, $level)
{
if (Auth::user() && Auth::user()->level !== $level) {
return App::abort(Auth::check() ? 403 : 401, Auth::check() ? 'Forbidden' : 'Unauthorized');
}
return $next($request);
}
}
//config/routes.php - configure routes for different levels and pass level as middleware parameter
Route::group(['middleware' => 'level:master'], function()
{
//here add routes for users with level=master
}
Route::group(['middleware' => 'level:portais'], function()
{
//here add routes for users with level=portais
}

Roles with laravel 5, how to allow only admin access to some root

I follow this tutorial : https://www.youtube.com/watch?v=kmJYVhG6UzM Currently I can check in my blade if user is a admin or not like this:
{{ Auth::user()->roles->toArray()[0]['role'] }}
HI ADMIN
#endif
How can I make my route only available for admin user?
You need to create a middleware for your route.
Use: php artisan make:middleware AdminMiddleware.
You will find in your middleware folder a new file with this name.
Put your logic in your middleware, e.g.
public function handle($request, Closure $next)
{
if(Auth::check())
{
return $next($request);
}
else
{
return view('auth.login')->withErrors('You are not logged in');
}
}
Once you have done your logic in your middleware, you can either call it in the route or make the middleware apply to all routes.
If you want to add it to all routes, go to Kernel.php and add it to the $middleware array, e.g.
protected $middleware = [
'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
'Illuminate\Cookie\Middleware\EncryptCookies',
'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
'Illuminate\Session\Middleware\StartSession',
'Illuminate\View\Middleware\ShareErrorsFromSession',
'App\Http\Middleware\VerifyCsrfToken',
'App\Http\Middleware\AdminMiddleware',
];
If you want to add it to specific routes only, add it to the $routeMiddleware variable and add the alias to the route. E.g.
protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
'admin' => 'App\Http\Middleware\AdminMiddleware',
];
You can then add it to a route, as a filter, e.g.
Route::get('admin/profile', ['middleware' => 'admin', function()
{
}]);
For additional info visit the docs:
http://laravel.com/docs/master/middleware
EDIT
An improvement on this would be to use variadic functions which was introduced in PHP 5.6
http://php.net/manual/en/migration56.new-features.php
Instead of having to make a middleware for each permission set you can do the following
PermissionMiddleware
namespace App\Http\Middleware;
use Closure;
use \App\Models\Role;
class PermissionMiddleware
{
// Pass parameters to this middleware
public function handle($request, Closure $next, ...$permitted_roles)
{
//Get a users role
$role = new Role;
$role_name = $role->getUserRoleByName();
foreach($permitted_roles as $permitted_role) {
if($permitted_role == $role_name) {
return $next($request);
}
}
return redirect()->back()->withErrors('You do not have the required permission');
}
}
Notice the ...$permitted_roles
Route::get('admin/profile', ['middleware' => 'PermissionMiddleware:Admin,Marketing', function()
{
}]);
You can now specify as many roles as required for one middleware rather than creating multiple by using middleware parameters
Docs
https://laravel.com/docs/5.3/middleware#middleware-parameters
Let's assume you have a column in your users table with isAdmin name which has a default value of 0 (false)
You can give special access using middleware in laravel like you give access to logged in users using auth middleware in laravel.
Now you need to create a middleware using the command :
php artisan make:middleware AdminMiddleware
In your Kernel.php you need to add this line to protected $routeMiddleware
'admin' => \App\Http\Middleware\AdminMiddleware::class,
In your middleware folder you have the AdminMiddleware file.
In that you need to put your logic
In this case this is how it might look like depending upon you
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RoleMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(Auth::user()->isAdmin == '1') // is an admin
{
return $next($request); // pass the admin
}
return redirect('/'); // not admin. redirect whereever you like
}
}
Now in your route you have to pass the url using this middleware
Here is how it might look like
Route::get('/iamanadmin', ['middleware' => 'admin', function() {
return view('iamanadmin');
}]);
use middleware and check for admin user.
Route::get('admin', ['middleware' => 'checkadmin', function()
{
}]);
now create middleware and validate admin user.

Categories