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");
Related
I have a method for checking if a user's role is an admin, if not, redirect them with return redirect('/')->send();. How can I check for user role and redirect the user without displaying the page and waiting for a redirect?
My Controller:
class AdminController extends Controller
{
public function __construct()
{
if (Auth::check())
{
$user = Auth::user();
if ($user->role != 'admin')
{
return redirect('/')->send();
}
}
else
{
return redirect('/')->send();
}
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return View('admin/index');
}
}
Create your own Middleware. Here is an example. In my example, I have several usergroups in a separate model. You have to change the code for your needs.
Create the Middleware via terminal/console:
php artisan make:middleware UserGroupMiddleware
The created middleware class could be find in app/Http/Middleware/UserGroupMiddleware.php
You need the following code in your middleware:
namespace App\Http\Middleware;
use Closure;
use App\User;
use App\Usergroup;
class UserGroupMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, $group)
{
if($request->user() !== NULL){
$userGroupId = $request->user()->group;
$userGroup = Usergroup::find($userGroupId);
if($userGroup->slug === $group){
return $next($request);
}
}
// Redirect the user to the loginpage
return redirect('/login');
}
}
Now you have to register this middleware in app/Http/Kernel.php:
protected $routeMiddleware = [
// other middlewares
// Custom Middleware
'group' => \App\Http\Middleware\UserGroupMiddleware::class
];
Finally you need to attach the middleware to your route:
Route::group(['middleware' => 'group:admin'], function(){
// Routes for admins, e.g.
Route::get('/dashboard', 'SomeController#dashboard');
});
// Or for a single route:
Route::get('/dashboard', ['middleware' => 'group:admin'], function(){
return view('adminbereich.dashboard');
});
Remember, that you could pass in multiple middlewares with:
Route::get('/some/route', ['middleware' => ['group:admin', 'auth']], 'SomeController#methodXYZ');
import redirect by adding this to the above the class
use Illuminate\Support\Facades\Redirect;
And the make your redirect by using
return Redirect::to('login');
I need help with a problem that I cannot solve by myself.
I'm using Laravel 5.1 and when I try to enable the Authenticate Middleware I receive this error.
ErrorException in Manager.php line 137:
call_user_func_array() expects parameter 1 to be a valid callback, class 'Illuminate\Auth\Guard' does not have a method 'handle'
I have the middleware as it comes by default with Laravel, also the kernel.php, both look like this
<?php
namespace Imuva\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class Authenticate {
/**
* 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->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('auth/login');
}
}
return $next($request);
}
}
And the kernel:
protected $routeMiddleware = [
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \Imuva\Http\Middleware\RedirectIfAuthenticated::class,
'auth' => \Imuva\Http\Middleware\Authenticate::class,
];
And I use it from here:
class HomeController extends Controller {
public function __construct() {
$this->middleware('auth', ['only' => 'admin']);
}
I dont know what could be happening at all. Thanks for reading
I think you are mixing up everything you found regarding middlewares.
Why calling $this->middleware('auth', ['only' => 'admin']); on your constructor? Have a read here
Your handle method signature is : public function handle($request, Closure $next). You are passing an array as well?
How do you mange your users roles?
I want to guest users have access to home page but in built in authentication process laravel redirects to login page. how can i give guest users access to home page?
my routes.php:
Route::group(['middleware' => 'web'], function () {
Route::auth();
Route::get('/', 'HomeController#index');
Route::get('/insert', 'HomeController#insertform');
Route::get('/job/{id}', 'JobsController#show');
Route::get('/city/{city}', 'JobsController#city');
Route::post('/insert', 'HomeController#insert');
Route::get('/cityinsert', 'HomeController#cityinsert');
Route::post('/cityinsert', 'HomeController#cityinsertpost');
});
and authenticate.php
class Authenticate
{
/**
* 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)->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('login');
}
}
return $next($request);
}
}
and this is my kernel.php
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
}
I prefer to exclude middleware via routes. You can do it in two ways:
Single action:
Route::post('login', 'LoginController#login')->withoutMiddleware(['auth']);
Group mode:
Route::group([
'prefix' => 'forgot-password',
'excluded_middleware' => ['auth'],
], function () {
Route::post('send-email', 'ForgotPasswordController#sendEmail');
Route::post('save-new-password', 'ForgotPasswordController#saveNewPassword');
});
Tested on Laravel 7.7
Add an exception in the middleware declaration in the construct
Route::get('/', 'HomeController#index');
for the above route to be exempted from authentication you should pass the function name to the middleware like below
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth', ['except' => 'index']);
}
}
Remove the middleware from HomeController construct:
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
//$this->middleware('auth');
}
}
I can add to Sidharth answer, that you can use several methods exeption, by including them in array:
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth', ['except' => ['index', 'show']]);
}
}
Laravel 5.5 tested.
You can also separate between middleware and except. Try this one :
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except([
'submitLogout',
'showUserDetail'
]);
}
Tested on Laravel 5.4
Add except URL to VerifyCsrfToken
app/http/middleware/VerifyCsrfToken.php
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
'stripe/*',
'http://example.com/foo/bar',
'http://example.com/foo/*',
];
}
Source: Laravel Documentation CSRF exclude URL
*Tested on Lavarel 7.0 as well
Recently I need that functionality in an old Laravel project.
God bless Laravel for macroable feature :)
AppServiceProvider.php
public function boot()
{
Route::macro('withoutMiddleware', function ($excludedMiddlewares) {
$this->action['middleware'] = array_filter(
$this->action['middleware'],
function ($middleware) use ($excludedMiddlewares) {
return !in_array($middleware, $excludedMiddlewares);
});
return $this;
});
}
Then you can use it like this:
Route::get('something')->withoutMiddleware(['auth']);
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']]
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.