I would like to authentificate some routes, if the user is admin.
Route::get( '/user/{data}', 'UserController#getData' );
Route::post( '/user/{data}', 'UserController#postData' );
Now, I made it inside the Controller:
public function getData( $data = 'one' )
{
if ( Auth::user()->permission == 'admin' ) {
//...
} else {
//...
}
}
public function postData( Request $request, $data = 'one' )
{
if ( Auth::user()->permission == 'admin' ) {
//...
} else {
//...
}
}
I would like to make it with Route::group, but how can I do that in the routes.php?
You can create middleware which will check if user is an admin:
class IsAdmin
{
public function handle($request, Closure $next)
{
if (Auth::user()->permission == 'admin') {
return $next($request);
}
return redirect()->route('some.route'); // If user is not an admin.
}
}
Register it in Kernel.php:
protected $routeMiddleware = [
....
'is.admin' => \App\Http\Middleware\IsAdmin::class,
];
And then apply it to a route group:
Route::group(['middleware' => 'is.admin'], function () {
Route::get('/user/{data}', 'UserController#getData');
Route::post('/user/{data}', 'UserController#postData');
});
You can specify a routes group and give it a middleware
https://laravel.com/docs/5.3/routing#route-groups
https://laravel.com/docs/5.3/middleware
https://laravel.com/docs/5.3/middleware#assigning-middleware-to-routes
Example:
routes.php
Route::group(['middleware' => 'admin'], function () {
Route::get( '/user/{data}', 'UserController#getData' );
Route::post( '/user/{data}', 'UserController#postData' );
});
app/Http/Middleware/admin.php
<?php
namespace App\Http\Middleware;
use Closure;
class Admin
{
public function handle($request, Closure $next)
{
if ( Auth::user()->permission !== 'admin' ) {
//
} else {
//
}
}
}
Related
Web.php
Route::group(['middleware'=>'auth:admin'], function(){
Route::resource('dashboard', 'DashboardController');
Route::group(['prefix'=>'users','namespace'=>'User','as'=>'u.'], function(){
Route::resource('list', 'ListController');
Route::resource('segments', 'SegmentController');
});
Route::group(['prefix'=>'sales','namespace'=>'Sales','as'=>'s.'], function(){
Route::resource('credits', 'CreditController');
Route::resource('packages', 'PackageController');
});
});
RedirectIfAuthenticated
class RedirectIfAuthenticated
{
public function handle($request, Closure $next, $guard)
{
if(Session::has('admin_session')){
return redirect('admin/dashboard');
}
// if (Auth::guard($guard)->check()) {
// return redirect(RouteServiceProvider::HOME);
// }
return $next($request);
}
}
AuthController
public function login(Request $request)
{
$serviceAccount = ServiceAccount::fromJsonFile(__DIR__.'/firebaseKey.json');
$firebase= (new Factory)->withServiceAccount($serviceAccount)->create();
$this->database = $firebase->getDatabase();
$auth = $firebase->getAuth();
// if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password])) {
// return redirect('admin/dashboard');
// }
try {
if($user = $auth->verifyPassword($request->email,$request->password)){
Session::put('admin_session',$user);
return redirect('admin/dashboard');
}
} catch (\Kreait\Firebase\Exception\Auth\InvalidPassword $e) {
echo 'wrong password'; die();
} catch (\Kreait\Firebase\Auth\SignIn\FailedToSignIn $e) {
echo 'invalid email'; die();
}
}
How to put only session authentication on above-mentioned routes?
As I want to put firebase authentication so laravel's wouldn't work here,
So I just want to implement simple isset(session('admin_session')) functionality which will be common for all routes...
Anyone, please suggest me how to implement it... it keeps redirecting!
Change the middleware group to a new middleware name:
Web.php
Route::group(['middleware'=>'role'], function(){ //or the name you want to use
Route::resource('dashboard', 'DashboardController');
Route::group(['prefix'=>'users','namespace'=>'User','as'=>'u.'], function(){
Route::resource('list', 'ListController');
Route::resource('segments', 'SegmentController');
});
Route::group(['prefix'=>'sales','namespace'=>'Sales','as'=>'s.'], function(){
Route::resource('credits', 'CreditController');
Route::resource('packages', 'PackageController');
});
});
Create a new middleware by php artisan make:middleware Role :
Role.php (Middleware)
<?php
namespace App\Http\Middleware;
use Session;
use Closure;
class Role
{
public function handle($request, Closure $next)
{
if(Session::has('admin_session')) {
return $next($request);
}
return redirect()->route('login');
}
}
Modify the RedirectIfAuthenticated middleware to this:
RedirectIfAuthenticated.php
class RedirectIfAuthenticated
{
public function handle($request, Closure $next, $guard = null)
{
if (Session::has('admin_session')) {
return redirect('admin/dashboard');
}
return $next($request);
}
}
Modify AuthController to this:
AuthController.php
public function login(Request $request)
{
if ($auth = $this->firebase->getAuth()) {
try {
$user = $auth->verifyPassword($request->email, $request->password);
Session::put('admin_session',$user);
return redirect('admin/dashboard');
}
catch (\Kreait\Firebase\Exception\Auth\InvalidPassword $e) {
return back(); // code for wrong password
}
catch (\Kreait\Firebase\Auth\SignIn\FailedToSignIn $e) {
return back(); //code for user doesn't exists
}
}
return back(); // something went wrong
}
how to create middleware redirect about role. I have 2 middleware, first Admin, next User. Need redirect after login, if role Admin, example redirect to /admin, if User redirect to /user.
Admin middleware:
if(Auth::check() && Auth::user()->isRole() == "Admin"){
return $next($request);
}
return redirect('login');
User middleware:
if(Auth::check() && Auth::user()->isRole() == "User"){
return $next($request);
}
return redirect('login');
WEB routes
Route::group(['middleware' => ['auth']], function () {
Route::get('/', 'DashboardController#index');
Route::group(['middleware' => ['auth' => 'admin']], function (){
Route::resource('/admin', 'AdminController');
});
Route::group(['middleware' => ['auth' => 'user']], function (){
Route::resource('/user', 'AdminController');
});
});
You can make your admin/user middleware to inherit laravel's Authenticate middleware: Illuminate\Auth\Middleware\Authenticate, then have their definitions as below.
Admin Middleware-
public function handle($request, Closure $next, ...$guards)
// Ensure auth - this will automagically re-direct if not authed.
$this->authenticate($request, $guards);
if(Auth::user()->isRole() == "Admin")
return $next($request);
return redirect('/user-default-page')
}
// You can define this for your un-authenticated redirects
protected function redirectTo($request)
{
return '/login';
}
User middleware will then be:-
public function handle($request, Closure $next, ...$guards)
// Ensure auth - this will automagically re-direct if not authed.
$this->authenticate($request, $guards);
if(Auth::user()->isRole() == "User")
return $next($request);
return redirect('/admin-default-page')
}
// You can define this for your un-authenticated redirects
protected function redirectTo($request)
{
return '/login';
}
For routes:
Route::group(['middleware' => 'admin'], function () {
// Put here admin routes, e.g
Route::resource('/admin', 'AdminController');
}
Route::group(['middleware' => 'user'], function () {
// Put here user routes, e.g
Route::resource('/users', 'UserController');
}
// You can still use the default auth routes, say for routes that (somehow), both admin and user can access
Route::group(['middleware' => 'auth'], function () {
Route::resource('/dashboard', 'DashboardController');
}
// Admin Middleware
public function handle($request, Closure $next)
{
if(Auth::check() && Auth::user()->role->id == 1)
{
return $next($request);
}else {
return redirect()->route('login');
}
}
// User Middleware
public function handle($request, Closure $next)
{
if(Auth::check() && Auth::user()->role->id == 2 )
{
return $next($request);
}else {
return redirect()->route('login');
}
}
// Admin Route Group
Route::group(['as'=>'admin.','prefix'=>'admin','namespace'=>'Admin','middleware'=>['auth','admin']], function (){
Route::get('dashboard','DashboardController#index')->name('dashboard');
})
// User Middleware
Route::group(['as'=>'user.','prefix'=>'user','namespace'=>'Author','middleware'=>['auth','user']], function (){
Route::get('dashboard','DashboardController#index')->name('dashboard');
});
i am trying to return back to departments after add a new department but this what happens :
Route [admin.departments.index] not defined
this is my store function in the DepartmentController
class DepartmentController extends BaseController
{
public function store(Request $request)
{
$this->validate($request, [
'department_name' => 'required|max:191',
]);
$params = $request->except('_token');
$department = $this->departmentRepository->createDepartment($params);
if (!$department) {
return $this->responseRedirectBack('Error occurred while creating department.', 'error', true, true);
}
return $this->responseRedirect('admin.deparments.index', 'Department added successfully' ,'success',false, false);
}
}
this is the responseRedirect function in the base controller
class BaseController extends Controller
{
protected function responseRedirect($route, $message, $type = 'info',
$error = false, $withOldInputWhenError = false)
{
$this->setFlashMessage($message, $type);
$this->showFlashMessages();
if ($error && $withOldInputWhenError) {
return redirect()->back()->withInput();
}
return redirect()->route($route);
}
}
these are the routes
Route::group(['prefix' => 'departments'], function() {
Route::get('/', 'Admin\DepartmentController#index')->name('admin.departments.index');
Route::get('/create', 'Admin\DepartmentController#create')->name('admin.departments.create');
Route::post('/store', 'Admin\DepartmentController#store')->name('admin.departments.store');
Route::get('/{id}/edit', 'Admin\DepartmentController#edit')->name('admin.departments.edit');
Route::post('/update', 'Admin\DepartmentController#update')->name('admin.departments.update');
Route::get('/{id}/delete', 'Admin\DepartmentController#delete')->name('admin.departments.delete');
});
InvalidArgumentException
Route [admin.deparments.index] not defined.
The store function in your DepartmentController returns a typo: admin.deparments.index should be admin.departments.index.
My roles are dynamic and their User's permission are also dynamic. I have two approaches to validate if the user is authorized to access the particular page.
Approach 1
class BaseController extends Controller
{
public function __construct() {
if(!\Auth::user()->IsPredefined) {
$result = $this->ValidateAuthorization();
if(!$result) {
\Auth::logout();
return redirect()->route("login");
}
}
}
private function ValidateAuthorization() {
$ActionName = \Route::getCurrentRoute()->getPath();
switch ($ActionName) {
case "ChangePassword":
$ModuleID = ModuleEnum::AccountManagemenet;
$ActionID = AccountActionEnum::ChangePassword;
return CheckUsePermissions($ModuleID, $ActionID);
}
}
private function CheckUsePermissions($ModuleID, $ActionID) {
$User = MySession::UserPermissions();
foreach($User->UserRolePermissions as $UserRolePermission) {
$CurrentActionID = $UserRolePermission->RolePermission->Permission->ActionID;
$CurrentModuleID = $UserRolePermission->RolePermission->Permission->ModuleID;
if($CurrentActionID == $ActionID && $CurrentModuleID == $ModuleID &&
$UserRolePermission->IsActive == true) {
return true;
}
}
return false;
}
}
Approach 2
Use Authorize method in Request class
public function authorize()
{
return true;
}
Confusion
If Approach 2 is good, should I create Request class for each Get, Put, Delete and POST?
Is there any better approach to validate authorization?
For Dynamic Roles I do something like this:
Let suppose I have following permissions:
Manage Users
Manage CMS
Manage Hotels
Manage Packages
Manage Roles
Now the Super Admin (who obviously has all the above permissions) can create a role, say, Hotel Manager and assign permission for only Manage Hotels.
Now for a route like:
Route::get('/admin/hotels', 'HotelsController#index')->name('admin.hotels.index');
I will put it in a Route Group with a middleware in it:
Route::group(['prefix' => '/admin/hotels', 'middleware' => ['permission:manage_hotels']], function () {
Route::get('/', 'HotelsController#index')->name('admin.hotels.index');
Route::post('/', 'HotelsController#create')->name('admin.hotels.create');
});
Then I will create a Permission middleware:
class Permission
{
public function handle($request, Closure $next, $permission)
{
//if not super admin (super admin role_id is 1)
if(auth()->user()->role_id != 1) {
//explode extra param passed to this middleware (here manage_hotels)
$permission_array = explode('_', $permission);
foreach ($permission_array as $key => $value) {
$permission_array[$key] = ucfirst($value);
}
$permission_name = implode(' ', $permission_array);
$permitted = auth()->user()->role->permissions()->where('name', $permission_name)->first();
if(! $permitted) {
return redirect()->route('admin.dashboard')->withErrors(['error' => ['message' => 'You are not allowed to perform this action.']]);
}
}
return $next($request);
}
}
Of course you'll need to wrap these routes into Admin Middleware which will ensure that user is logged in and has an admin role.
You should use middleware and use in routes
Route::group(['middleware' => ['auth', 'admin']], function () { });
Or you can use in every controller constructor
public function __construct()
{
$this->middleware('auth');
$this->middleware('admin');
}
Admin middleware like
class AdminAuthenticate
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::check()) {
if (Auth::user()->IsPredefined) {
$result = $this->ValidateAuthorization();
if(!$result) {
return redirect('/logout');
}
}
}
return $next($request);
}
}
I have a question about filtering a controller and its actions for multiple user roles. Lets say i have a controller named MyController :
public class MyController extends \BaseController
{
public static function index()
{
}
public static function show()
{
}
public static function create()
{
}
public static function store()
{
}
public static function other()
{
}
}
And i have 2 filters for each roles, named admin and staff :
Route::filter('admin', function()
{
// Lines of code to get role
if($role != 'admin') return View::make('errors.401');
});
Route::filter('staff', function()
{
// Lines of code to get role
if($role != 'staff') return View::make('errors.401');
});
Then, i'm trying to use beforeFilter on the constructor of MyController :
public function __construct()
{
$this->beforeFilter('admin', ['only' => ['index', 'show', 'create', 'store']]);
$this->beforeFilter('staff', ['only' => ['index', 'show']]);
}
When I added the first beforeFilter, it works as I expected (when I logged in to my application as staff, I cannot access the index, show, create, and store methods). But when I added the second filter and logged in as staff again, I cannot access the index and show actions, which is I expected to be accessible by staff.
My questions are, is it possible to define filters for multiple roles in the constructor of a controller? (In this case, I want to make action index and show accessible by admin and staff, but create and store only accessible by admin) And if it is possible, how could I achieve that?
Thanks.
First you should make a controller that should handle access control ... as below
Acl Controller
class ACLController extends \BaseController {
/**
* admin access control list
* #return array
*/
private function adminACL() {
return array(
'users' => array(
'users',
'users.show',
//similar access list for admin users
),
);
}
/**
* staff access control list
* #return array
*/
private function staffACL() {
return array(
'staff' => array(
'staff',
'staff.index',
//similar access list for staff user
),
);
}
//Method that check access of related user
/**
* check access level
* #param string $value
* #return boolean
*/
public function hasAccessLevel($value) {
$user = //get user role here
if ($user->roles == 'staff') {
return TRUE;
} elseif ($user->roles == 'admin') {
$newAcl = array();
foreach ($this->adminACL() as $aclBreak) {
foreach ($aclBreak as $acl) {
$newAcl[] = $acl;
}
}
if (!in_array($value, $newAcl)) {
return FALSE;
} else {
return TRUE;
}
} else {
$newAcl = array();
foreach ($this->staffACL() as $aclBreak) {
foreach ($aclBreak as $acl) {
$newAcl[] = $acl;
}
}
if (!in_array($value, $newAcl)) {
return FALSE;
} else {
return TRUE;
}
}
}
}
Filter the access route...
Route::filter('hasAccess',function($route,$request,$value){
try{
$Routeacl = new App\Controllers\ACLController();
if(!$acl->hasAccessLevel($value))
{
return Redirect::to('admin/dashboard')->withErrors(array(Lang::get('en.user_noaccess')));
}
}catch(\Exception $e){
echo $e->getMessage();
}
});
And then in your route just check if it has access
Route::get('/', array('as' => 'index', 'before' => 'hasAccess:index', 'uses' => 'MyController#Index'));
Happy coding :)
I assume you have Admin can access all feature, and staff can access everything except "show"
This is the controller
class MyController extends \BaseController
{
public function __construct(){
$this->beforeFilter('admin', ['only' => ['show']]);
}
public function index()
{
echo "index";
}
public function show()
{
echo "show";
}
}
See in your last post, you are using public class, I believe in PHP you will just need class, in function better don't use static.
Here is the filters.php
Route::filter('admin', function()
{
// Lines of code to get role
if($role != 'admin') return "This is only for admin";
});
In the routes.php
Route::get("/my", "MyController#index");
Route::get("/show", "MyController#show");
Then try to login as admin, you will can access "index" and "show"
Then try to login as staff, you will can access "index" but cannot access "show"
Is an admin always a staff member? If so - you could just do this:
Route::filter('staff', function()
{
// Lines of code to get role
if(($role != 'staff') && ($role != 'admin'))return View::make('errors.401');
});