Laravel make a resource available to only guest users - php

This is my route:
Route::group(array('before' => 'auth'), function() {
Route::resource('restaurants', 'RestaurantsController');
});
I want the restaurants.create to be available for guest users.
Is that possible?

Just declare the route outside of the Route Group like this:
Route::resource('restaurants', 'RestaurantsController');
Instead of this:
Route::group(array('before' => 'auth'), function() {
Route::resource('restaurants', 'RestaurantsController');
});
Then in your RestaurantsController controller add the before filter inside the __construct method like this:
public function __construct()
{
parent::__construct(); // If BaseController has a __construct method
$this->beforeFilter('auth', array('except' => array('create')));
}
So all the methods will have auth as the before filter but without the create method. If you need to add another before filter then you may add another one just after the first one like this:
public function __construct()
{
parent::__construct(); // If BaseController has a __construct method
// Add auth as before filter for all methods but not for create
$this->beforeFilter('auth', array('except' => array('create')));
// Only for create method
$this->beforeFilter('anotherFilter', array('only' => array('create')));
}

I believe you're looking for the guest filter, which should be included by default.
So change the line from:
Route::group(array('before' => 'auth'), function() {
to:
Route::group(array('before' => 'guest'), function() {

Related

Laravel authorization via middleware

I created a policy in laravel 5.3 with this two actions:
class ProjectPolicy {
...
public function index(User $user)
{
return true;
}
public function create(User $user)
{
return true;
}
...
}
and then I tried to make authorization via route group middleware:
Route::group(['middleware' => ['can:index,create,App\Project']], function () {
Route::resource('projects', 'ProjectController');
});
ofcourse I have created Project model and controller correctly, but calling index and create actions always returns 403 forbidden response. where is the problem?
Update:
removing one of actions from route middleware, results correct response. something like this:
Route::group(['middleware' => ['can:index,App\Project']], function () {
Route::resource('projects', 'ProjectController');
});
Looking through the docs the can middleware doesn't really lend itself to resources. You could use multiple middleware calls on the group but this would mean that your use would require all privileges to access the routes.
Your alternatives are:
Add $this->authorize(new App\Project) to your index and create methods in your controller. Laravel will use reflection to figure out what policy to use based on the method it is called from.
Or
In the __construct() method of your controller you could use:
$this->authorizeResource(App\Project::class);
This will require you to
create update, view and delete methods inside your Policy class. Each of these methods will be passed User $user, Project $project e.g.
public function view(User $user, Project $project)
{
return true;
}
FYI, if you leave off the method name with authorize() or you use authorizeResource() Laravel will map certain method names to different policy methods i.e. :
[
//ControllerMethod => PolicyMethod
'show' => 'view',
'create' => 'create',
'store' => 'create',
'edit' => 'update',
'update' => 'update',
'destroy' => 'delete',
];
You can override this by adding a resourceAbilityMap() method to your controller and returning a different array to the one above.
Hope this helps!
Spend hours on that ...
If your controller method does not take a Model as parameter, you also have to override the resourceMethodsWithoutModels().
protected function resourceAbilityMap()
{
Log::info("Inside resourceAbilityMap()");
return array_merge(parent::resourceAbilityMap(), [
//ControllerMethod => PolicyMethod
'index' => 'index',
'search' => 'search'
]);
}
protected function resourceMethodsWithoutModels(){
return array_merge(parent::resourceMethodsWithoutModels(), [
'search'
]);
}

Laravel route Action not defined

I am having trouble with Laravel routes. I'm trying to redirect to a controller after some middleware in the routes. But there is always this error.
The error is:
InvalidArgumentException in UrlGenerator.php line 558: Action
App\Http\Controllers\DashboardController#index not defined.
The route code is:
Route::get('/dashboard', ['middleware' => 'auth', function() {
return Redirect::action('DashboardController#index', array('user' => \Auth::user()));
}]);
The controller:
class DashboardController extends Controller
{
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
return view('dashboard')->with('user', \Auth::user());
}
}
But the above code actually works (so I guess that the controller actually works):
Route::get('/testdashboard', [
'uses' => 'DashboardController#index'
]);
So what is the problem? What is a valid route action?
This is might a better way to do it, change from
Route::get('/dashboard', ['middleware' => 'auth', function() {
return Redirect::action('DashboardController#index',
array('user' => \Auth::user()));
}]);
to
Route::get('/', [
'middleware' => 'auth',
'uses' => 'DashboardController#index'
]);
This is rather a comment than a post, but I can't send it at this time. I don't undestand why do you pass parameter (\Auth:user()) to a method that doesn't require it (but it's correct when you do it for the View).
Anyways I suggest you to work on your Middleware
public function handle($request, Closure $next)
{
if (Auth::check()) {
return redirect(...);
} else {
return redirect(...);
}
}
Use this route in place of your route and upgrade your Laravel Project to Laravel 8:
Route::middleware(['auth:sanctum', 'verified'])->group(function () {
Route::get('/dashboard', 'DashboardController#index')->name('daskboard');
});

Single Laravel Route for multiple controllers

I am creating a project where i have multiple user types, eg. superadmin, admin, managers etc. Once the user is authenticated, the system checks the user type and sends him to the respective controller. The middle ware for this is working fine.
So when manager goes to http://example.com/dashboard he will see the managers dashboard while when admin goes to the same link he can see the admin dashboard.
The below route groups work fine individually but when placed together only the last one works.
/***** Routes.php ****/
// SuperAdmin Routes
Route::group(['middleware' => 'App\Http\Middleware\SuperAdminMiddleware'], function () {
Route::get('dashboard', 'SuperAdmin\dashboard#index'); // SuperAdmin Dashboard
Route::get('users', 'SuperAdmin\manageUsers#index'); // SuperAdmin Users
});
// Admin Routes
Route::group(['middleware' => 'App\Http\Middleware\AdminMiddleware'], function () {
Route::get('dashboard', 'Admin\dashboard#index'); // Admin Dashboard
Route::get('users', 'Admin\manageUsers#index'); // Admin Users
});
I know we can rename the routes like superadmin/dashboard and admin/dashboard but i was wondering if there is any other way to achieve the clean route. Does anyone know of any anywork arounds ?
BTW i am using LARAVEL 5.1
Any help is appreciated :)
You can do this with a Before Middleware that overrides the route action's namespace, uses and controller attributes:
use Closure;
use Illuminate\Http\Request;
use Illuminate\Contracts\Container\Container;
use App\Http\Middleware\AdminMiddleware;
use App\Http\Middleware\SuperAdminMiddleware;
class AdminRoutingMiddleware
{
/**
* #var Container
*/
private $container;
public function __construct(Container $container)
{
$this->container = $container;
}
private static $ROLES = [
'admin' => [
'namespace' => 'Admin',
'middleware' => AdminMiddleware::class,
],
'super' => [
'namespace' => 'SuperAdmin',
'middleware' => SuperAdminMiddleware::class,
]
];
public function handle(Request $request, Closure $next)
{
$action = $request->route()->getAction();
$role = static::$ROLES[$request->user()->role];
$namespace = $action['namespace'] . '\\' . $role['namespace'];
$action['uses'] = str_replace($action['namespace'], $namespace, $action['uses']);
$action['controller'] = str_replace($action['namespace'], $namespace, $action['controller']);
$action['namespace'] = $namespace;
$request->route()->setAction($action);
return $this->container->make($role['middleware'])->handle($request, $next);
}
}
This way you have to register each route only once without the final namespace prefix:
Route::group(['middleware' => 'App\Http\Middleware\AdminRoutingMiddleware'], function () {
Route::get('dashboard', 'dashboard#index');
Route::get('users', 'manageUsers#index');
});
The middleware will convert 'dashboard#index' to 'Admin\dashboard#index' or 'SuperAdmin\dashboard#index' depending on current user's role attribute as well as apply the role specific middleware.
The best solution I can think is to create one controller that manages all the pages for the users.
example in routes.php file:
Route::get('dashboard', 'PagesController#dashboard');
Route::get('users', 'PagesController#manageUsers');
your PagesController.php file:
protected $user;
public function __construct()
{
$this->user = Auth::user();
}
public function dashboard(){
//you have to define 'isSuperAdmin' and 'isAdmin' functions inside your user model or somewhere else
if($this->user->isSuperAdmin()){
$controller = app()->make('SuperAdminController');
return $controller->callAction('dashboard');
}
if($this->user->isAdmin()){
$controller = app()->make('AdminController');
return $controller->callAction('dashboard');
}
}
public function manageUsers(){
if($this->user->isSuperAdmin()){
$controller = app()->make('SuperAdminController');
return $controller->callAction('manageUsers');
}
if($this->user->isAdmin()){
$controller = app()->make('AdminController');
return $controller->callAction('manageUsers');
}
}

Laravel 5 - before auth not working

Today I tried to make some changes to my application. I tried to pass all pages through authentication first. I tried one of the answer on this site. But that didn't help. Please help. Here's my code in routes.php
<?php
Route::get('/', function(){
return view('homepage');
});
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
Route::group(['before' => 'auth'], function () {
Route::get('home', function(){
return \Redirect::to('twitter');
});
Route::get('twitter', 'HomeController#index');
.
.
.
.
});
There are several routes in my file. But only twitter route works.
In laravel 5,
['before' => 'auth']
is deprecated. But instead, I should use
['middleware' => 'auth']
Laravel5 has middlewares instead of filter. I assume you are trying to show certain page to only guests and for that we have a guest middleware already built in.
Route::group(['middleware' => 'guest'], function () {
Route::get('home', function(){
return \Redirect::to('twitter');
});
Route::get('twitter', 'HomeController#index');
});
you may also use middlewares on particular functions of your controller if you want, e.g
class MyController extends Controller {
public function __construct()
{
//to add auth middleware only on update method
$this->middleware('auth', ['only' => 'update'])
//to add auth middleware on all fucntions expcept login
$this->middleware('auth', ['except' => 'login'])
}
}

Laravel 4: protecting routes provided by a controller

I'm building a Laravel 4 app and I want to protect my admin area so it is only accessible if the user is logged in/authenticated.
What is the best way to do this?
The Laravel docs say you can protect a route like this:
Route::get('profile', array('before' => 'auth', function()
{
// Only authenticated users may enter...
}));
But what happens when my route looks like this:
Route::resource('cms', 'PostsController');
How do I protect a route that is directing to a controller?
Thanks in advance!
You could use Route Groups for this purpose.
So for example:
Route::group(array('before' => 'auth'), function()
{
Route::get('profile', function()
{
// Has Auth Filter
});
Route::resource('cms', 'PostsController');
// You can use Route::resource togehter with
// direct routes to the Resource Controller
// so e.g. Route::post('cms', 'PostsController#save');
});
You can put the filter on the constructor of your Controller like this:
public function __construct()
{
$this->beforeFilter('auth');
$this->beforeFilter('csrf', array('on' => 'post'));
$this->afterFilter('log', array('only' =>
array('fooAction', 'barAction')));
}
In your PostsController you can put a closure in the constructor to do the same before logic as the previous route.
public function __construct()
{
$this->beforeFilter(function()
{
//
});
}

Categories