Laravel 5.2 lock controller for some users - laravel

I want to lock AccountsController for all the users expect users for admin users..
For Exampe:
Auth::user() -> roll != 'Admin' then close the AccountsController..
AccountsController Construct Code:
public function __construct()
{
$this->middleware('auth');
}

Middleware is a completely valid solution for this, but I have switched to Gates for this type of situation. Gate is a bit more convenient to use. I use roles and permissions and a hasRole method to manage the level of access, but if your system is simple you can easily just have a isAdmin method on your User model that checks a flag in the database.
Middleware
Create you custome middleware.
AuthenticateAdmin.php
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class AuthenticateAdmin {
protected $auth;
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
public function handle($request, Closure $next)
{
if ($this->auth->user()->hasRole('admin'))
{
return $next($request);
}
}
}
Add that to your Kernel.
Kernel.php
protected $routeMiddleware = [
'auth' => Middleware\Authenticate::class,
'auth.admin' => Middleware\AuthenticateAdmin::class,
];
Then you can use the middleware in your controllers.
public function __construct()
{
$this->middleware('auth.admin');
}
Gate
With Gate you add you define your policy in AuthServiceProvider
AuthServiceProvider.php
public function boot(GateContract $gate)
{
parent::registerPolicies($gate);
$gate->define('user-admin', function($user){
return $user->hasRole('admin');
});
}
Then add it to your controller or where ever you need it.
Controller.php
public function show($slug)
{
if (Gate::allows('user-admin')){
return $yes;
}
return $no;
}

Related

How can I use multiple middlewares on the same route name in Laravel 9?

I want my /dashboard page to be a different panel in 2 different user types. And return to home screen if not logged in. I created 2 middlewares to check if logged in user is "employer" or "employee". Whatever I do, I can't seem to make it work, it's been 2 days. I created middlewares and routes by following some very sketchy tutorials, it may hurt your eyes, be aware.
My route:
Route::get('/dashboard', function () {
return view('welcome');
})->name('welcome');
Route::prefix('admin')->middleware([\App\Http\Middleware\isEmployer::class])->group( function () {
Route::get("/dashboard", function (){
return view("employer.dashboard");
})->name("dashboard");
});
Route::prefix('store')->middleware([\App\Http\Middleware\isEmployee::class])->group( function(){
Route::get("/dashboard", function (){
return view("employee.dashboard");
})->name("dashboard");
});
isEmployee middleware:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class isEmployee
{
public function handle(Request $request, Closure $next)
{
if(Auth::user())
{
if (Auth::user()->role == "employee")
{
return $next($request);
}
}
return response()->view('welcome');
}
}
isEmployer middleware :
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class isEmployer
{
public function handle(Request $request, Closure $next)
{
if(Auth::user())
{
if (Auth::user()->role == "employer")
{
return $next($request);
}
}
return response()->view('welcome');
}
}
What I want to achieve is:
if not logged in : return welcome view
if logged in as employer : return employer.dashboard view
if logged in as employee : return employee.dashboard view
Let's start from some refactoring:
Make your routes/web.php a bit more readable:
Route::view('/dashboard', 'welcome')->name('welcome');
Route::prefix('admin')->name('admin.')->middleware('role:employer')->group(function() {
Route::view('/dashboard', 'employer.dashboard')->name("dashboard");
});
Route::prefix('store')->name('store.')->middleware('role:employee')->group(function() {
Route::view('/dashboard', 'employee.dashboard')->name("dashboard");
});
Now let's create a middleware that will check not only for one role, but for any role you give as a parameter:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class HasRole
{
public function handle(Request $request, Closure $next, string $role)
{
if (Auth::user()?->role != $role) {
return redirect()->route('welcome');
}
return $next($request);
}
}
Now, create an alias in your app/Http/Kernel.php so you could use it like i wrote it in routes file role:<role_here>:
protected $routeMiddleware = [
// ...
'role' => \App\Http\Middleware\HasRole::class,
];
Now for your question - how to use multiple middlewares for one route. It is simple:
$route->middleware(['middleware1', 'middleware2']);
You may attach them to groups or single routes:
Route::prefix('some_group')->middleware(['middleware1', 'middleware2'])->group(function() {
Route::view("some.view")->middleware('middleware3')->name("some.view");
});
You can read more info about Laravel's middlewares here, and understand what responsibility chain is (pattern which middleware implements) under the hood. Also take a look at SOLID principles, mainly at DRY one. Have a good day =)

Laravel: How the best way for redirect a default laravel user to admin page if user is admin or to user page if user is not admin?

The User model has an isAdmin() function to check if the user is an administrator. What to do next?
The best way is to use default laravel LoginController located under App\Http\Controllers\Auth\LoginController.
In that controller you can override authenticated method that is injected from AuthenticatesUsers trait, by simply adding that method in LoginController:
* #param Request $request
* #param $user
*/
protected function authenticated(Request $request, $user)
{
if ($user->isAdmin()) {
return redirect(route('admin-dashboard'));
//redirect to desired place since user is admin.
}
}
Best practique is whit roles, and you add role on your Routes::middleware,
Route::group(['middleware' => ['auth', 'roles:admin']], function () {
//Your routes
});
Kernel.php
'roles' => Middleware\CheckRole::class,
Create middleware
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
public function handle($request, Closure $next, ...$role)
{
if ($request->user()->hasAnyRole($role)) {
return $next($request);
}
return redirect(route('hour'));
}
}
create function on User model
public function authorizeRole($role)
{
if ($this->hasAnyRole($role)) {
return true;
}
return abort(401, 'Unauthorized.');
}
public function hasAnyRole($roles)
{
if (is_array($roles)) {
foreach ($roles as $role) {
if ($this->hasRole($role)) {
return true;
}
}
} else {
if ($this->hasRole($roles)) {
return true;
}
}
return false;
}
public function hasRole($role)
{
if ($this->role()->where('name', $role)->first()) {
return true;
}
return false;
}
public function role()
{
return $this->belongsTo('App\Role')->withDefault();
}
And Role model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
public function user()
{
return $this->hasMany('App\User');
}
}
Is more code, but best way for this action

How do I validate User role on Laravel 5.8s Built in Authentication?

I've a User Role column on my User's table.
stands for Super Admin,
stands for other users
I've checked a lot of Laravel Tutorials and none of them has helped me about solving this issue.
I've found ways like replacing the whole Laravel's Login Controller and replacing Authenticate Users trait with ours own. I want to solve my problem with minimal code change. Is it possible?
How do I implement it with minimal code changes in this Trait method?
public function login(Request $request)
{
$this->validateLogin($request);
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
You could do something as supersimple as adding a isSuperAdmin function to the User model. After logging in you just call this function on the user whenever you need to check.
In model User.php
public function isSuperAdmin()
{
return $this->user_role == 1;
}
Then you could also make a middleware that's using this function.
php artisan make:middleware SuperAdmin
In the handle function of this middleware (app/http/middleware/SuperAdmin.php):
public function handle($request, Closure $next)
{
if (Auth::check() && Auth::user()->isSuperAdmin()) {
return $next($request);
}
return redirect('some-route-for-unauthorized-users');
}
Then in your routes (probably web.php), you can use this middleware to protect routes:
Route::group(['middleware' => ['auth', 'superadmin']], function () {
... put protected routes here ...
});
Solution
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct() {
$this->middleware('guest')->except('logout');
}
protected function credentials(Request $request)
{
$credentials = $request->only($this->username(), 'password');
$credentials['role'] = '1';
return $credentials;
}

How to get current user id in constructor in laravel?

I am using laravel 5.7, but i can't get current user id in __construct().
I also tried Auth:id(), but it also not working.
How to get current user id in constructor?
use Illuminate\Support\Facades\Auth;
class TestController extends Controller
{
public $id;
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next) {
$this->id = Auth::user()->id;
return $next($request);
});
dd($this->id);
}
}
Current output is null.
You can only access the session in the closure. Just refactor your code to this:
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next) {
$this->id = Auth::user()->id;
dd($this->id);
return $next($request);
});
}
You can now use the value $this->id in your controller methods.
In the example in your question, after you've set the value $this->id, you continue with the request. Since you try to access $this->id outside of the scope of the closure, it still is null in the datadump.
After return you will not go to next statement that's why it is not print.
If you want to use this in view then no need to pass in view you can simply access logged user id like this
{{Auth->user->id}}
if you wan to use this in controller make sure you are logged in.
Sometime session expired then you will not get user id
use Illuminate\Support\Facades\Auth;
class TestController extends Controller
{
public $id;
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next) {
$this->id = Auth::user()->id;
dd($this->id);
return $next($request);
});
}
}
The easiest solution is to create a middleware and call it later in the constructor.
php artisan make:middleware FoobarMiddleware
I recommend putting an alias in Kernel.php
protected $routeMiddleware = [
...
'foobar' => \App\Http\Middleware\FoobarMiddleware::class,
]
Constructor:
public function __construct()
{
$this->middleware('auth');
$this->middleware('foobar');
}
I recommend changing the focus of how you are creating everything

Laravel validation site belongs to user

My User.php
class User extends Authenticatable
{
public function sites()
{
return $this->hasMany(Site::class);
}
}
My Site.php
class Site extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
My routes.php
Route::resource('site', 'SiteController');
My SiteController.php
class SiteController extends Controller
{
public function edit(int $id)
{
$site = Auth::user()->sites()->find($id);
return view('site.edit', compact('site'));
}
}
How can I validate that the site belongs to user? I understand that in my case if site doesn't belong to user, $site variable will be null. But I want more declarative way, something like laravel requests, because I need the same check in show, update, and destroy methods. But I cannot use laravel request, because checking is something like this
$siteId = Route::current()->param('site');
$ids = Auth::user()->sites()->pluck('id')->toArray();
$result = in_array($siteId, $ids);
Can anyone suggest how to achieve my goal?
Since I use laravel 5.2, solution with route filters is deprecated. Instead route filter we should use middleware.
app/Http/Middleware/RestrictPermission.php
class RestrictPermission
{
public function handle($request, Closure $next)
{
$siteId = Route::current()->parameter('site');
if (!Auth::user()->sites()->find($siteId)) {
abort(403);
}
return $next($request);
}
}
app/Http/Kernel.php
class Kernel extends HttpKernel
{
protected $routeMiddleware = [
'restrict.permission' => RestrictPermission::class,
];
}
SiteController.php
class SiteController extends Controller
{
public function __construct()
{
$this->middleware('restrict.permission', ['except' => [
'index', 'create', 'store',
]]);
}
public function edit(int $id)
{
$site = Auth::user()->sites()->find($id);
return view('site.edit', compact('site'));
}
}

Resources