Restricting Pages to Admins - Laravel - php

I am having a tutorial on how to restrict pages to admins. In my RedirectIfAuthenticated.php, this is how my code looks like
public function handle($request, Closure $next, $guard = null)
{
if (!Auth::guard($guard)->check()) {
// return redirect('/login');
} else {
$user = Auth::user();
if($user->hasRole('manager')) {
return redirect('admin/home');
} else {
return redirect('/home');
}
}
return $next($request);
}
After i login, i am routed to the respective pages but the issue is, i can still route to the admin page even tho i login as a member and not manager. When i place localhost/admin/home, i am still routed to that page although i am not a manager. What am i missing out?

You are able to access the manager url after login because your code only redirects each user to their appropriate url's but does'nt do any other check after the users are logged in. You can accomplish this by creating a middleware to check for each user type and redirect them to their appropriate pages and attach this middleware to your desired routes.
In your terminal, run php artisan make:middleware AdminMiddleware to create a middleware Note: the AdminMiddleware is a name of my choosing and can be changed.
This creates a middleware in the app\Middlewares directory. edit the contents to look like this..
<?php
namespace App\Http\Middleware;
use Closure;
class AdminMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Auth::user();
if(!$user->hasRole('manager'))
{
//you can throw a 401 unauthorized error here instead of redirecting back
return redirect()->back(); //this redirects all non-admins back to their previous url's
}
return $next($request);
}
}
Then go to the app/Http/Kernel.php file and add the following to the $routeMiddleware array.
'admin' => \App\Http\Middleware\AdminMiddleware::class,
Now you can attach the admin middleware to any route which you would like only managers to access.

Related

Laravel how to add middleware to controller with multiple roles?

What I want to achieve is that the EventController's functions/ methods should be available for role:organizer, and only the view() method [URL: /events/{id}] from the same controller should also be available to role:artist.
I've tried to implement that by creating the following middleware to check for the logged-in user's role:
class UserRole
{
/**
* Handle an incoming request.
*
* #param Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return Application|JsonResponse|RedirectResponse|Redirector
*/
public function handle(Request $request, Closure $next, ...$roles)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
if (!Auth::check()) {
return redirect(RouteServiceProvider::HOME);
}
if (in_array(strtolower(Auth::user()->type), $roles)) {
return $next($request);
}
return redirect('/login');
}
}
Then in my EventController, I have assigned the following middlewares in the constructor:
public function __construct()
{
$this->middleware(['auth', 'verified', 'onboarding', 'role:organizer']);
$this->middleware(['role:artist,organizer'])->only('view');
}
When I run php artisan route:list - I get the list as I want it to be, only events/{id} has both the organizer and artist role
However when I log in with user artist and try to access localhost/events/10 - I get redirected to the /login screen, but when I try to access the same URL with a role organizer it works..
Is there any suggestion on how to make it work? If there's something you don't understand let me know and I'll help you!
The problem is that you have attached the middleware to view endpoint with 'role:organizer' twice in the first time it only check is user has role organizer and it doing redirect and it's not going check the second time so to exclude this behavior you should attache middlewares like this
$this->middleware(['auth', 'verified', 'onboarding']);
$this->middleware(['role:artist,organizer'])->only('view');
$this->middleware('role:organizer')->except('view');// because it already added above

Laravel 8 + Jetsream: How to Redirect to Prior Page After Login?

I have a basic web page where I want the user to be able to click the login link, go through the login, and then be returned to that page (not the home page). The page has some features that can only be seen when the user is logged in.
I am having trouble with this, no matter what when I go to login it returns to the home page after authentication or whatever I have set as the constant, not the prior page.
Fortify.php has a home path that is a constant, so I can't update that with an expression either...
'home' => RouteServiceProvider::HOME,
Here is the middleware RedirectIfAuthenticated.php, it is the standard Laravel and I'm wondering what would need to be updated.
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null ...$guards
* #return mixed
*/
public function handle(Request $request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
}
return $next($request);
}
}
I should note too, that if I add a middleware route to the page, as in the below example, then the process works correctly as far as returning the user back to the prior page.
Route::middleware(['auth:sanctum', 'verified'])->get('/agenda', function () {
return view('agenda');
})->name('agenda');
However, I need the user to be able to view the agenda page, even if they are a guest... but, once logged in, they will be returned to the agenda page which will have some additional features. I can't seem to find in the documentation anything about this, unfortunately.
In AuthenticatesUsers.php
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
if ($response = $this->authenticated($request, $this->guard()->user())) {
return $response;
}
return $request->wantsJson()
? new JsonResponse([], 204)
: redirect()->back();
}
Or You Can Do this in Your Default Login Controller in Line 31
protected $redirectTo = "/your-path";
When the auth middleware detects an unauthenticated user, it will redirect the user to the login named route. You may modify this behavior by updating the redirectTo function in your application's app/Http/Middleware/Authenticate.php file
https://laravel.com/docs/8.x/authentication#redirecting-unauthenticated-users

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');

Laravel 6 Error: On entering login route app crashes

I'll try to explain my issue as much as possible. I just created a Laravel application. Whenever I'm logged in either as a user or admin (user route is http://localhost/Folder/ and admin route is http://localhost/Folder/admin) and I enter the login view path i.e. http://localhost/Folder/login
it takes me to this page: http://localhost/Folder/home with error message Page Not Found
I have not added any route of /home in my routes. What I want is on entering the login path, the user should stay on the same page if he is logged in. And the same case for admin instead of going to this path. http://localhost/Folder/home.
Here are the routes for user and admin:
Route::get('/','HomeController#index')->name('home')->middleware(['auth','XSS']);
Route::group(['middleware' => ['auth','admin']], function()
{ Route::get('/admin/dashboard','HomeController#home_page')->name('admin.home');
});
Here is my login controller:
protected function redirectTo(){
if (Auth::user()->user_type == 'admin') {
//return 'admin.dashboard';
return redirect('/admin/dashboard');
}
else {
//return 'home';
return redirect('/');
}
}
And my AdminMiddleware
public function handle($request, Closure $next)
{
if(Auth::user()->user_type == 'admin') //If usertype is admin
{
return $next($request);
}
else {
// return redirect('home');
return redirect()->route('/');
}
}
All I want is that it should remain logged in while entering the login page route. I'll be happy to provide any other details if required. Any suggestions/solutions will be highly appreciated.
Edit the route in the RedirectIfAuthenticated middleware
It will redirect to /home if it finds that you are already logged in and try to access the login page.
You need to overload redirectTo method on loginController which you have done and update redirectIfAuthenticated to match your logic.
So go-to your loginController and update
protected function redirectTo() {your logic like you have done}
Also you will need to update redirectIfAuthenticated middleware to match your logic
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
return $next($request);
}
}
Also if admin/dashboard is always going to be the home route for your auth and admin middleware. Then instead of changing redirectIfAuthenticated.php just change the HOME constant on routeserviceprovider.php in providers and change to
Const HOME = 'admin/dashboard';
Thanks everyone for your suggestions. I just tried something and it worked.
In the RedirectIfAuthenticated.php file:
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/home');
}
return $next($request);
}
Just changed return redirect('/home');
to
return redirect('/');
And it worked...

How to add custom middleware inside a Route group in laravel

I have a Route group in laravel which has middleware of auth
Route::group(['middleware'=>'auth', function()
{
//Routes
});
Now these routes are only available to logged in users. I have a situation that logged in users have privileges. I have some routes that are only to be visited by logged in users AND if they have privilege of OWNER
In function I have started a session and stored privilege value.
I did something like this
Route::group(['middleware'=>'auth', function()
{
//Routes
if(session::get('privilege')
{
//Routes
}
});
This isn't working neither it's appropriate method. Can anyone tell me how add middleware inside a middleware?
There should be no logic inside your routes file(s) - these should simply define routes and nothing else. What you should do is define middleware which verifies privileges/roles your user has, you can specify parameters which are passed to the middleware like this:
Route::group(['middleware' => 'auth', function() {
Route::get('/my-route', 'Controller#method')->middleware('role:some_role');
Route::get('/my-other-route', 'Controller#otherMethod')->middleware('role:some_other_role');
});
Then in your middleware, you can access that parameter via a third argument in the handle method. With that value, you could verify the privileged/role the user has and then decide if the user should access that route:
public function handle($request, Closure $next, $role)
{
// Do something with $role
return $next($request);
}
If you're unsure about defining your own custom middleware, check out the docs here: https://laravel.com/docs/middleware
You will need to create a custom middleware called OWNER
php artisan make:middleware Owner
Will create a middleware file for you.
Then in the public function called handle u can do something like
if (Auth::user()->privilege == "OWNER") {
return $next($request);
}
return redirect('home');
So at the end your custom middleware will look something like this:
<?php
namespace App\Http\Middleware;
use Closure;
class Owner
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::user()->privilege == "OWNER") {
return $next($request);
}
return redirect('home');
}
}
More about Laravel Middelware here

Categories