I want to add additional middleware to user model. User table has row 'approved' which is boolean (default is false). So when user logins - middleware should check if 'approved' is equal to true. If not, redirect to error page. What i got so far:
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
class ConfirmedMiddleware
{
public function handle($request, Closure $next, $guard = null)
{
if(Auth::user()->approved != true){
redirect('/error');
}
return $next($request);
}
}
So far middleware attached here:
Route::get('/home', 'HomeController#index')->middleware('confirmed')->name('home');
However, it does not work. No errors as well.
You're better off checking this when a user logins instead of using a middleware.
Add this to the LoginController and perform any additional checks. This method will be called after the user successfully logs in.
protected function authenticated($request, $user)
{
if($user->approved != true){
return redirect('/error');
}
}
If you still insist on using middleware, then make sure you add the middleware in Kernel.php
Add this in app/Http/Kernel.php
'confirmed' => \App\Http\Middleware\ConfirmedMiddleware::class,
You're also missing the return in your redirect.
public function handle($request, Closure $next, $guard = null)
{
if(Auth::user()->approved != true){
return redirect('/error');
}
return $next($request);
}
You are missing the return in the redirect, It should be:
return redirect('/error');
Related
I am working on a project in which I have three type of users Admin and user1 and user2. I want user1 and user2 to able to use certain features in application only if the admin has assigned an invoice to them. I have tried using helper function given below.
$invoice = Invoice::pluck('user_id')->toArray();
if (Auth::user()->admin == 1 || in_array(Auth::user()->id, $invoice)) {
return 1;
} else {
return 0;
}
but this does not work fine. I'll have to place it before every method of a controller in order to restrains users to use that feature. Is there any thing else I can do?
Any Better Approach for this?
You can use middlewares.
Create your middleware with
php artisan make:middleware UserWithInvoiceMiddleware
Then open your file in app/Http/Middleware/UserWithInvoiceMiddleware.php, and add this to the handle method:
public function handle($request, Closure $next, ...$guards)
{
$user = auth()->user();
$invoice = Invoice::pluck('user_id')->toArray();
if ($user->admin || in_array($user->id, $invoice)) {
return $next($request);
}
return response()->json(['message' => 'Request not authorized.'], 401);
}
Also, you can create a relation in your user model with the Invoice model:
public function invoice()
{
return $this->hasOne(Invoice::class);
}
Then, you can simplify your middleware using this relation:
public function handle($request, Closure $next, ...$guards)
{
if (auth()->user()->admin || auth()->user()->has('invoice')) {
return $next($request);
}
return response()->json(['message' => 'Request not authorized.'], 401);
}
You have to register your middleware in app/Http/Kernel.php, under the $routeMiddleware array:
protected $routeMiddleware = [
...
'user-with-invoice' => App\Http\Middleware\UserWithInvoiceMiddleware::class,
];
Then, you can protect your routes with this middleware, adding a ->middleware('user-with-invoice') to the routes where the user has to be an admin or have an invoice:
Route::get('/example', ExampleController::class)->middleware('user-with-invoice');
you can use make a middleware and pass requests throw it to check if the user is authorized to do that or not.
class SomeMidllewareName
{
/**
* Handle an incoming request.
*
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$invoice = Invoice::pluck('user_id')->toArray();
if (1 == Auth::user()->admin || in_array(Auth::user()->id, $invoice)) {
return $next($request);
}
return \response()->json(['message' => 'you are not authorized'], 401);
}
}
then, you can validate on the routes and you can use also policies and validate every feature alone
I have a problem when I want to pass data to the view via the middleware to count the number of users. when not using middleware, variable from controller get to the view.
my HomeController.php
public function index()
{
$count = User::count();
return view('admin.Dashboard', compact($count);
}
my Middleware
public function handle(Request $request, Closure $next)
{
if ($request->user() && $request->user()->role == 'admin') {
return response()->view('admin.Dashboard');
} else {
return response()->view('member.dashboard');
}
return $next($request);
}
the $count variable if using middleware in route not passed to the view
my web.php
Auth::routes(['verify' => true]);
Route::get('/dashboard', 'HomeController#index')->middleware('verified', 'cekrole')->name('home');
In your middleware you are returning response (a view), so
return $next($request);
will never be executed, so neither will your controller.
User call /dashboard > Your middleware is called > if it's an admin you are returning admin.Dashboard, else member.dashboard.
But you never execute code in your Controller.
As a quick fix you could replace your Middleware by :
public function handle(Request $request, Closure $next)
{
if ($request->user() && $request->user()->role == 'admin') {
$count = User::count();
return view('admin.Dashboard', compact('count'));
}
return response()->view('member.dashboard');
}
or make those test (admin/not admin) in your controller
This is the code of my Middleware.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use App\Models\Role;
use App\User_roles;
use App\User;
use Route;
class OwnerMiddleware
{
public function handle($request, Closure $next)
{
$user = new User;
$current = $user->find(Auth::user()->id)->role;
$current = $current->find($current->id)->roles;
if($current->name != 'admin' && $current->name != 'oper')
{
return redirect('/');
}
return $next($request);
}
}
And this is the code of web.php
Route::group(['middleware'=>'auth'],function(){
Route::group(['middleware'=>'role'],function (){
Route::resource('users','UseCon');
});
Route::group(['middleware'=>'role:client'],function (){
});
Route::group(['middleware'=>'role:oper'],function (){
Route::get('operall', 'ApplicController#index');
Route::get('operall/drivers', 'DriversController#index')->name('driver_page');
});
});
My Question is :how can I prevent url (/ users) from going to the user whose role is:oper ?
NOTE: role (oper) should not go to those urls that roles are available
(admin)
For protecting your user routes, you can create a User middleware
php artisan make:middleware User
In App\Http\Middleware\User.php you can do something like this
public function handle($request, Closure $next)
{
// Check if user has permission to access route
if(!Auth::user()->role === 'user' ) {
return redirect()->back();
}
return $next($request);
}
Register middleware in the kernel.php
protected $routeMiddleware = [
...
'user' => \App\Http\Middleware\User::class
];
Then protect user routes with created user middleware
Route::group(['middleware'=> 'user'],function (){
Route::resource('users','UseCon');
});
Repeat same steps for 'admin' and 'oper' routes.
I want the guest to access Home and Shop page and still verifies email when a user wants to register.
Route::get('/home', 'HomeController#index')->name('home')->middleware('verified');
The EnsureEmailIsVerified middleware requires the user to be logged in to access any pages protected with it.
You can see this check in the code for the middleware
if (!$request->user() ||
($request->user() instanceof MustVerifyEmail &&
!$request->user()->hasVerifiedEmail())) {
// reject
}
If you want to allow guests to access the page, and still require users to be activated you will need to create a custom middleware.
php artisan make:middleware GuestOrActivated
Then, for the handle function:
public function handle($request, Closure $next, $redirectToRoute = null)
{
if ($request->user() && $request->user() instanceof MustVerifyEmail && !$request->user()->hasVerifiedEmail()) {
return $request->expectsJson()
? abort(403, 'Your email address is not verified.')
: Redirect::route($redirectToRoute ?: 'verification.notice');
}
return $next($request);
}
For that case I make new middleware, before redirect to email verify, I flush the session, so when user back to home, he will redirect to login again
class GuestOrActivated
{
public function handle($request, Closure $next, $redirectToRoute = null)
{
if ($request->user() && $request->user() instanceof MustVerifyEmail && !$request->user()->hasVerifiedEmail()) {
request()->session()->flush();
return Redirect::route('verification.notice');
}
return $next($request);
}
}
I have three type of users for the application, Each one have its own dashboard. I need a check that adminor any other user cannot see another user dashboard.
There is a middleware RedirectIfAuthenticated :
public function handle($request, Closure $next, $guard = null){
if (Auth::guard($guard)->check() && auth()->user()->type == 'admin'){
return redirect('/admin');
}
if (Auth::guard($guard)->check() && auth()->user()->type == 'author'){
return redirect('/author');
}
if (Auth::guard($guard)->check() && auth()->user()->type == 'client'){
return redirect('/client');
}
}
Its under guest middleware.
The above code seems good to me but when i tests it, The browser says Too many redirects.
What am i doing wrong, What will be the best way to handle it.
You may have misunderstood the purpose of that middleware. The purpose of RedirectIfAuthenticated is to redirect a user to their default authenticated page. It is not meant to block unauthenticated/unauthorised users from accessing specific areas.
What you need to do is redirect if not authorised. Since this is a simple case you can just have a middleware:
class RequireRole {
public function handle($request, Closure $next, $role) {
abort_unless(auth()->check() && auth()->user()->type == $role, 403, "You don't have permissions to access this area");
return $next($request);
}
}
Then register this middleware in your Kernel.php
protected $routeMiddleware = [
//Other middleware
"requirerole" => RequireRole::class
];
Then you can use it in your routes e.g.
Route::get('/admin', function () { /* action */ })->middleware("requirerole:admin");
However if you find yourself in need of more complex rules then take a look at Authorization
Need to modify the code a bit
public function handle($request, Closure $next, $guard = null){
if (Auth::guard($guard)->check() && auth()->user()->type == 'admin'){
return redirect('/admin');
}
if (Auth::guard($guard)->check() && auth()->user()->type == 'author'){
return redirect('/author');
}
if (Auth::guard($guard)->check() && auth()->user()->type == 'client'){
return redirect('/client');
}
return $next($request);
}
You have to add an extra check for every if statement to see if you are not already on the route where it's going to redirect to
Maybe something like:
&& $request->is('admin')
Just split your checks and keep the original return:
public function handle($request, Closure $next, $guard = null){
if (Auth::guard($guard)->check()){
if(Auth::user()->type == 'admin'){
return redirect('/admin');
}
if(Auth::user()->type == 'author'){
return redirect('/author');
}
if(Auth::user()->type == 'client'){
return redirect('/client');
}
}
return $next($request);
}
As pointed in the accepted answer, the purpose of the middleware is to redirect a user if he is authenticated.
Now if you check App\Http\Kernel.php you will see that the middleware is attached to guest route middleware variable.
So any route you assign the middleware of guest will not be accessible to an authenticated user.
To solve your problem create another middle as pointed in the accepted answer.
What you need to do is redirect if not authorised. Since this is a simple case you can
just have a middleware:
public function handle($request, Closure $next, $role) {
abort_unless(auth()->check() && auth()->user()->type == $role, 403, "You don't > have permissions to access this area");
return $next($request);
}
}
Then register this middleware in your Kernel.php
//Other middleware
"requirerole" => RequireRole::class
];
Then you can use it in your routes e.g.
Route::get('/admin', function () { /* action */ })->middleware("requirerole:admin");
In reality, you may not need to modify default files that come with laravel unless it is inevitable.