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
});
});
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 have two guards in laravel
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
//Our Admin custom driver
'web_admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
and providers
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
//Admin user provider
'admins' => [
'driver' => 'eloquent', //We are using eloquent model
'model' => App\Admin::class,
],
],
The default is
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
When i log in as admin and try to access the user profile it asks me to login as user which is normal. But what im looking for is, admin should be able to access whole site as admin login.
The reason i choose multi auth over rbac is because i have 5 types of users and each have different registration fields and login. Each user have a set of tools too.
So i want admin guard to be able to access all guards too.
Business guard to be able to access only users guard.
App/Http/Controllers/AdminAuth/LoginController
<?php
//LoginController.php
namespace App\Http\Controllers\AdminAuth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
//Class needed for login and Logout logic
use Illuminate\Foundation\Auth\AuthenticatesUsers;
//Auth facade
use Auth;
class LoginController extends Controller
{
//Where to redirect admin after login.
protected $redirectTo = '/admin/home';
//Trait
use AuthenticatesUsers;
//Custom guard for admin
protected function guard()
{
return Auth::guard('web_admin');
}
//Shows admin login form
public function showLoginForm()
{
return view('admin.auth.login');
}
}
App/Http/Controllers/Auth/LoginController
<?php
namespace App\Http\Controllers\Auth;
use Socialite;
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');
}
/**
* Redirect the user to the GitHub authentication page.
*
* #return \Illuminate\Http\Response
*/
public function redirectToProvider($social)
{
return Socialite::driver($social)->redirect();
}
/**
* Obtain the user information from GitHub.
*
* #return \Illuminate\Http\Response
*/
public function handleProviderCallback($social)
{
$user = Socialite::driver($social)->user();
// $user->token;
}
}
Similarly i have created middleware for admin too in App/Https/Middleware/AuthenticateAdmin.php
<?php
//AuthenticateAdmin.php
namespace App\Http\Middleware;
use Closure;
//Auth Facade
use Auth;
class AuthenticateAdmin
{
public function handle($request, Closure $next)
{
//If request does not comes from logged in admin
//then he shall be redirected to admin Login page
if (! Auth::guard('web_admin')->check()) {
return redirect('/admin/login');
}
return $next($request);
}
}
And RedirectIfAdminAuthenticated
<?php
//RedirectIfAdminAuthenticated.php
namespace App\Http\Middleware;
use Closure;
//Auth Facade
use Auth;
class RedirectIfAdminAuthenticated
{
public function handle($request, Closure $next)
{
//If request comes from logged in user, he will
//be redirect to home page.
if (Auth::guard()->check()) {
return redirect('/home');
}
//If request comes from logged in admin, he will
//be redirected to admin's home page.
if (Auth::guard('web_admin')->check()) {
return redirect('/admin/home');
}
return $next($request);
}
}
RedicrectIfAuthenticated
<?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);
}
}
Further to our correspondence
1.
If you have many types of users... so i suggest you to change your logic and make the Admin as User too... remove the admins and in the users add field "type" or something like that... and work with field to check if user is admin or have permission / access to some parts of the system... and if the user "type" is "admin" so he will have access to all parts too.
so you mean remove multi auth and go for RBAC. But i have a requirement where i need to use multi auth and each guard has their own RBAC For example, admin guard roles are manager, support and so. Business guard roles are vendors, sellers and so.
yes this is what i mean. I did similar thing on one of the systems that i developed, and i added one more guard so all the "logged in" routes pass in (like auth) and there i'm checking the requested rout and action and check if the user type is allow to access this action, and if not i redirected him to somewhere else (in my case to main dashboard page).
add new middleware
php artisan make:middleware Permissions
in app\Http\Kernel.php, add to protected $routeMiddleware new middleware
'permissions' => \App\Http\Middleware\Permissions::class,
in Routes web add the desire routs for logged in and add the middleware permissions ... pay attention to the as definition
Route::group(['middleware'=>['auth', 'permissions']], function() {
// any of your routs ... for example
Route::get('/', [
'uses'=>"UserController#getUsers",
'as'=>"users"
]);
Route::get('/{id}', [
'uses'=>"UserController#getUserEdit",
'as'=>"users.edit"
]);
});
in the new middleware app\Http\Middleware\Permissions.php,
adjust the public function handle and add there the users level logic... pay attention that for the switch case checking the as ... the same as that defined in the routs web file.
add more check as you need for the logged in user "type"... Admin, Support ... and so on as you have in the system.
public function handle($request, Closure $next, $guard = null)
{
$user = $request->user();
$actions = $request->route()->getAction();
switch( $actions['as'] ) {
case "users":
if( ! $user->isAdmin() ) {
//return redirect()->route("dashboard");
}
break;
case "users.edit":
if( ! $user->isAdmin() ) {
}
break;
// add more cases as you need and check the user "type"
default:
break;
}
return $next($request);
}
if you have a lot of routs... so maybe it will be better to add few "little" middleware and for every route group / prefix ... check if user allow to access this prefix.
for example... add SupportMiddleware / SalesMiddleware ... and in every one of them you can just check the user type and if it's fit to the current group of routes.
Simply, seperate your guards with , (comma) then all of the listed guards can access those routes.
Example:
Route::group(['middleware'=>'auth:web,web_admin'], function() {
//Now this routes can be accessible by both admin as well as
});
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 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.