Goal
I'm trying to create Admin route restriction for my log-in users.
I've tried a check to see if my user is log-in, and also if the user type is Admin, and if they are, I want to allow them access to the admin route, otherwise, respond a 404.
routes.php
<!-- Route group -->
$router->group(['middleware' => 'auth'], function() {
<!-- No Restriction -->
Route::get('dashboard','WelcomeController#index');
<!-- Admin Only -->
if(Auth::check()){
if ( Auth::user()->type == "Admin" ){
//Report
Route::get('report','ReportController#index');
Route::get('report/create', array('as'=>'report.create', 'uses'=>'ReportController#create'));
Route::post('report/store','ReportController#store');
Route::get('report/{id}', array('before' =>'profile', 'uses'=>'ReportController#show'));
Route::get('report/{id}/edit', 'ReportController#edit');
Route::put('report/{id}/update', array('as'=>'report.update', 'uses'=>'ReportController#update'));
Route::delete('report/{id}/destroy',array('as'=>'report.destroy', 'uses'=>'ReportController#destroy'));
}
}
});
Result
It's not working as I intended. It throws 404 error - even for Admin users.
You can use Middleware for this simple case.
Create middleware:
php artisan make:middleware AdminMiddleware
namespace App\Http\Middleware;
use App\Article;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class AdminMiddleware
{
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->getUser()->type !== "admin") {
abort(403, 'Unauthorized action.');
}
return $next($request);
}
}
Add it to app\Http\Kernel.php:
protected $routeMiddleware = [
'admin' => 'App\Http\Middleware\AdminMiddleware',
];
Use middleware in your routes:
Route::group(['middleware' => ['auth', 'admin']], function() {
// your routes
});
This answer is about why your code doesn't work as expected. #limonte 's solution is correct and the best I can think of.
Your routes file is parsed to get your routes, and after that, those routes might be cached somewhere else.
Thus you shouldn't put any code that depends on the request (eg checking whether a User has sufficient rights to access a route).
In particular, you shouldn't use the following request dependent modules inside your routes.php (not exhaustive) :
Auth
DB or any kind of db queries that might depend on time
Session
Request
You should view your routes.php as part of your config, it just happens that it is written in php directly instead of some new language you have to learn.
Related
I am using this package spatie/laravel-permission and what I want to do is:
super-admin, admin, members have the same login and after logged in it redirect to different routes.
The super-admin and admin have the same redirect. So I put this code.
//app\Http\Controllers\Auth\LoginController.php
protected function authenticated(Request $request, $user)
{
if ( $user->hasAnyRole(['super-admin', 'admin']) ) {// do your margic here
return redirect()->route('admin.dashboard');
}
return redirect('/home');
}
and then this is my routes
//routes/web.php
Auth::routes();
Route::group(['middleware' => ['role:member']], function () {
Route::get('/', 'HomeController#index')->name('home');
});
Route::group(['middleware' => ['role:super-admin|admin'], 'prefix' => 'admin'], function () {
Route::get('/', 'Admin\HomeController#dashboard')->name('admin.dashboard');
});
After login, what I want to do is when a super-admin/admin visit the site.com/* it should redirect to site.com/admin/ cause he is not authorize cause he is not a member and also when a member visit the site.com/admin/*, he redirect to site.com/ cause he is not admin/super-admin, the rest will go to login page when not authenticated.
It displays like this,
It should redirect based on their role homepage instead display 403 error.
Well, based on the package's middleware, there's no redirection logic involved. It is just checking if it has the correct permissions and throwing an unauthorized exception if the user does not.
You would need to write your own custom middleware, where you will check whether the user has the appropriate roles and to redirect to the appropriate url. A very simplistic example would be something like this (in the case of an admin).
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class CheckIfAdmin
{
/**
* 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 ( $user->hasAnyRole(['super-admin', 'admin']) ) {
return $next($request);
}
return redirect('/');
}
}
You would then attach this middleware instead of the other one.
I am trying to create an app that does nothing besides log a user in through the Socialite plugin.
Everything is working fine, I am redirected to facebook, the new user is created, and then when the user is redirected to '/', the user is mysteriously logged out.
(Note, this doesn't happen locally. On my local machine everything works fine).
Facebook Login Controller:
public function handleFacebookCallback()
{
$socialiteUser = Socialite::driver('facebook')->stateless()->user();
$user = $this->findOrCreateUser('facebook', $socialiteUser);
Auth::login($user, true);
return redirect('/');
}
Routes file:
Route::get('/', 'Home#home')->name('home')->middleware('auth');
Route::get('/home', 'Home#home')->name('home')->middleware('auth');
Route::get('/login', 'Controller#welcome')->name('welcome');
Auth::routes();
Route::get('/logout', 'Auth\LoginController#logout');
Route::get('facebook', function() {
return view('facebook');
});
Route::get('auth/facebook', 'Auth\FacebookController#redirectToFacebook');
Route::get('auth/facebook/callback', 'Auth\FacebookController#handleFacebookCallback');
Login Controller:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}
Middleware/RedirectIfAuthenticated.php:
namespace App\Http\Middleware;
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('/home');
}
return $next($request);
}
}
There is no defined "auth" middleware in my middlewares folder. It is done automatically through laravel.
AGAIN: this project works as intended LOCALLY, but not on the server.
final note: when I dd(Auth::check()) IMMEDIATELY before redirecting to '/', even on the server, I get "true", but then when I dd the same thing on the login page i get false. So somehow the user is being logged out on the redirect.
This is your problem Route::get('/', 'Home#home')->name('home')->middleware('auth');
You are using auth middleware in your \ path.
If you don't know what does that middleware do i recommend you this https://laravel.com/docs/5.6/authentication#protecting-routes
Your route should be
Route::get('/', 'Home#home')->name('home');
But you should modify this too, becouse they are using the same controller
Route::get('/home', 'Home#home')->name('home')->middleware('auth');
Another solution could be checking the URL's at developer facebook page.
Laravel 5.1 really had minimal documentation..
I need clear idea about how to protect routes using Auth middileware..
Documentation tells to add "middleware" => "auth" parameter to route.
or can do
public function __construct()
{
$this->middleware('auth');
}
But How to use Auth middleware for actual user authentication and auto redirection to /login from protected routes ??
In Kernel.php - there are registered middlewares under protected $routeMiddleware like this:
/**
* The application's route middleware.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
];
You can see 'auth' is registered for using App\Http\Middleware\Authenticate.
Then you can follow this path - if you open /app/Http/Middleware/Authenticate.php,
you will find public function handle:
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('auth/login');
}
}
return $next($request);
}
and here is where redirection is managed, and you can modify it for your own needs, or you can create custom middleware.
finally - as it is written in documentation - in the controller, which will need to be authenticated, you will add
public function __construct()
{
$this->middleware('auth');
}
You can create a custom middleware if provided ones do not suit your needs.
On laravel 5.2 if you want to hide the registration form or the login form views you should use your middleware as:
$this->middleware('mymiddleware', ['only' => ['register', 'showRegistrationForm', 'login', 'showLoginForm']]);
OR
$this->middleware('mymiddleware', ['except' => ['register', 'showRegistrationForm', 'login', 'showLoginForm']]);
That is because the register and login routes are the post methods on the AuthController while showXxxxForm are the form views.
Hope it helps anyone.
In Laravel, Middleware is used make to some Routes are access only to the User when User is login, Otherwise it will redirect to the Login Page.
Auth::routes();
Route::middleware(['auth'])->group(function () {
//After Login the routes are accept by the loginUsers...
}
Route::middleware(['admin'])->group(function(){
//the Admin is logged in to access the Routes...
}
//login authentication using middleware
1) make middleware:
php artisan make:middleware adminAuth
2) write in middleware file:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class loginAuth
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$isAuthenticatedAdmin = (Auth::check());
//This will be excecuted if the new authentication fails.
if (!$isAuthenticatedAdmin){
return redirect()->route('login')->with('message', 'Authentication Error.');
}
return $next($request);
}
}
3) add app/http/kernal.php inside below line
protected $routeMiddleware = [
'adminAuth' => \App\Http\Middleware\AdminAuth::class //Registering New Middleware
];
4)add routes in middleware:
Route::get('login',[AuthController::class,'index'])->name('login'); //named route
Route::get('dashboard',function(){
return view('admin-page.dashboard');
})->middleware("adminAuth");
I have a common login for both admin and user. But I have created a roles in my table which looks like:
user_id role_id
1 2
2 1
3 2
where role_id 1 refers to the admin and role_id 2 refers to the user. I can attach roles to the different user as well. Now what I want is, I want to protect all admin routes and user routes.
For example, I don't want user to get any access that is meant for admin. For now, I can check whether the user is admin or user like if (Auth::user()->hasRole('admin')) or if (Auth::user()->hasRole('user')).
How should I separate my user routes from admin routes in this case? Should I make my own middleware and implement? If so, how to implement it correctly?
Create two middleware, for admin you can do:
<?php namespace App\Http\Middleware;
use Auth;
use Illuminate\Contracts\Routing\Middleware;
class CheckAdmin implements Middleware {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::user()->hasRole('admin'))
{
return $next($request);
}
throw new \Exception("Unauthorized");
}
}
Then enable this middleware in App\Http\Kernel
protected $routeMiddleware = [
'auth' = 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'checkAdmin' => 'App\Http\Middleware\CheckAdmin',
];
You can use your CheckAdmin middlware in the routes.php file or in the constructor of your Controller
In routes.php you can do:
Route::group(['middleware' => 'checkAdmin'], function () {
Route::get('admin/profile', function () {
// Uses CheckAdmin Middleware
});
});
I have created two middleware in order to protect user route and admin routes
my UserMiddleware looks like this
<?php
namespace App\Http\Middleware;
use Auth;
use Closure;
class UserMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::user()->hasRole('user')) {
return $next($request);
}
throw new \Exception("Unauthorized");
}
}
and this is my Adminmiddleware
<?php
namespace App\Http\Middleware;
use Auth;
use Closure;
use App\Role;
class AdminMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::user()->hasRole('admin')) {
return $next($request);
}
throw new \Exception("Unauthorized");
}
}
Now what i want is when admin is logging in, i want a admin dashboard to open and when user is logging in, i want user dashboard to open, but now, it is redirecting me only to the admin route only when I try to login from user and admin, I have my user protected routes like this
Route::group(['middleware' => 'auth', 'user'], function () {
//all user routes
});
and admin protected routes
Route::group(['middleware' => 'auth', 'admin'], function () {
//all admin routes
});
and in my kernel.php, I have also added
'admin' => \App\Http\Middleware\AdminMiddleware::class,
'user' => \App\Http\Middleware\UserMiddleware::class,
and this is how I have validated a login in my controller
$loginData = array(
'email' => Input::get('email'),
'password' => Input::get('password'),
'confirmed' => 1
);
/*
* Checking against the record in database whether the email and password is valid
* Or the record exists in the database
*/
if (Auth::validate($loginData)) {
if (Auth::attempt($loginData)) {
return Redirect::intended('dashboard');
}
}
else {
// if any error send back with message.
Session::flash('error', 'Invalid Email/Password Combination');
return Redirect::to('login');
}
how can I make my middleware work and show admin dashboard when admin logs and user dashboard when user logs in. This has created a big problem for me.
First of all, if you want to show unauthorized users the login form, your middleware should redirect to login form. In order to have it, replace
throw new \Exception("Unauthorized");
with
return redirect(route('login'));
Secondly, your login controller should redirect users to the dashboard corresponding to their roles. In order to get the proper redirect, replace
if (Auth::attempt($loginData)) {
return Redirect::intended('dashboard');
}
with
if (Auth::attempt($loginData)) {
return Redirect::intended(Auth::user()->hasRole('admin') ? 'admin_dashboard' : 'user_dashboard');
}
The last issue is that you apply middleware to your routes incorrectly. If you want to apply multiple middlewares, you need to pass a list as middleware paramter. Replace
['middleware' => 'auth', 'user']
with
['middleware' => ['auth', 'user']]