I have two resources /test and /blabla.
For the /test I have registered middleware. In the middleware, based on certain condition, I would like to redirect current call to the controller/action which serve /blabla resource, transparently for user (no any extra client request, no 302 status response code etc..). How can I achieve it ?
It seems like your solution might be better suited in the routes file. You are suggesting serving a different route given a certain condition.
So in your routes.php file:
Route::get('test', function(){
if($condition){
return App::make('App\Http\Controllers\TestController')->index();
} else {
return App::make('App\Http\Controllers\BlaBlaController')->index();
}
});
If you still want to handle it in the middleware you should be able to do the same thing as above:
return App::make($controller)->index(); // or whatever controller method you want to call.
If you need both sets of middlewares to be called, then inside the constructor (after calling your middlewares) check your condition and call the other controller like above.
If you want to change the users url, I don't think there's any way other than returning a redirect. Most users don't notice the redirect so it will probably seem "transparent."
In that case, your middleware function looks like:
public function handle($request, Closure $next)
{
if (something == thingy) {
return redirect('/blabla');
}
return $next($request);
}
Related
The parameter is posted to some_name like this:
{{ route('some_name', $id = '1'}}
How can I access it in the if condition?
Route::group(['prefix' => '/'], function()
{
if ( condition )
{
Route::get('/route/{id}', 'ControllerA#methodA')->name('some_name');
} else{
Route::get('/route{id}', 'ControllerB#methodB')->name('some_name');;
}
});
How can I use the {id} parameter in the if (condition)?
I tried
Route::group(['prefix' => '/'], function($id)
{
if ( $id == 1)
And it's not working.
I think the best thing you can do is a Middleware, for example:
public function handle($request, Closure $next)
{
if ($request->id == 'some_value') {
redirect action('ControllerA#methodA');
}
else {
redirect action('ControllerB#methodB');
}
return $next($request);
}
Check the docs, personally i've never done an if inside my routes folder, besides that, it's really dangerous to practice stuff like that, make everything happen in the views, if you are messing up with user logged in or not, do auth::check() or something like that, but never play with the routes web.php to ensure security in your app, everything else is made on the controllers and views.
I don't think it's a good practice to validate the id in the route file to redirect to different controllers, and heres why:
You'll send a request to that endpoint and send an ID.
Is that ID valid? How do you know?
Is the ID an integer or a string?
Does ID exists in the request?
and with these 3 questions, you'll end up having validations + redirect to different methods and if it's an ID of interest to a database query, you'll have database code in there aswell.
The normal procedure I like to think is when it hits the route, it should hit Authorization and Authentication (middleware as Bak87 said). In there, you can validate if he's authenticated, if he's a certain user, whatever you'd like.
Afterwards this initial validation, you can redirect it to a certain method in a certain controller depending on your needs, however, I wouldn't advise as a class should have a single purpose according to some standards (but in the end, you can build the application how you want it).
I believe a route or a group of routes should have an middleware (for whatever primary validation you require of the person making the request), and each route should point to a single method in a controller. Once it reaches the controller, instead of having (Request $request) as the parameters for the method, you can have your own custom FormRequest, where you can validate the ID if you'd like.
If FormRequest isn't of interest, you can use Eloquent (if the ID you're looking for is related to it) FindOrFail to validate if it exists (if it doesn't, returns a 404 error not found, if you have a 404.blade.php file). This way, by the time it reaches the controller's method, it has been validated by sections, where routes are then protected by the main Authorization and Authentication, FormRequest to do the input's validation and you can specifically return whatever you'd like from the controller's method.
Obviously we don't know what is the view your returning but if slighty differs from each other, consider refactoring it in order to return only 1 view, composed of other blades
I'm writing a server based solution. In database there are many users with different permissions and I have to check if they have permission to access module they are trying to.
In every Controller I have included something like:
protected $module = "moduleName";
I tried to solve it like:
function __construct()
{
$perm = session()->get('perm');
if (!isset($perm[$this->module]) || !$perm[$this->module]) {
Session::flash('message_error', "<span class='glyphicon glyphicon-warning-sign'></span> Access denined!");
return back();
}
}
It shows the message but it still displays the page not redirects back.
As you see I'm reading permissions from session and modules name is saved in controller so I don't think this could be solved by middleware unless I'm making middleware for each module (I'm talking about 30 modules).
Thanks for taking the time to read this
Middleware actually solved this.
Route:
Route::group(['middleware' => 'module:moduleName'], function () {
// Routes...
});
Custom middleware:
public function handle($request, Closure $next, $module)
{
$perm = session()->get('perm');
if (!isset($perm[$module]) || !$perm[$module]) {
Session::flash('message_error', "<span class='glyphicon glyphicon-warning-sign'></span> Access denined!");
return redirect()->back();
}
return $next($request);
}
Also I'll mention that Route groups can be nested. So you can wrap multiple groups with something like auth middleware as well
There is a very easy fix to your code, you forgot the define the redirect, so instead of using
return back();
use
return redirect()->back();
This will do the redirect.
There is also a mistake in your reasoning, you could and probably should use middleware.
Middleware does have access to the user, session and can be passed parameters. These are the necessary requirements for your system.
You can also assign middleware on a controller basis.
I have (schematically) the following situation:
MiddlewareGroup1{
MiddlewareGroup2{
Route::resource(...);
...
Route::post('some-ajax-request', 'SomeController#action');
}
OtherNestedMiddlewareGroups{
...
}
}
I have the problem that I want MiddlewareGroup2 to apply for the ajax route, but not MiddlewareGroup1. How can I make MiddlewareGroup1 not apply, but keep MiddlewareGroup2?
I guess there is not built in solution here. You can put this route outside MiddlewareGroup1 or you could check current request url in MiddlewareGroup1, like:
....
if ($request->is('some-ajax-request')) {
return $next($request);
}
....
This will skip MiddlewareGroup1 middleware for defined URL(s).
If you have many similar ajax routes, you could use similar URLs for them ('ajax-add-stuff', 'ajax-do-some-stuff' etc) and check them like this:
if ($request->is('ajax*')) { .... }
I am using Laravel 5.1. My controller is specifically for admin users. So I check whether user is admin or not.This is my code.
public function getAdminData()
{
$this->checkAdminStatus();
return response()->json(array('admin-data'));
}
public function checkAdminStatus()
{
$userManager = new UserManager();
if(!$userManager->isAdmin())
{
return redirect()->route('returnForbiddenAccess');
}
}
My route is
Route::any('api/app/forbidden',['uses' =>'ErrorController#returnNonAdminErrorStatus','as'=>'returnForbiddenAccess']);
Now if user is not admin, then it should not return admin-data yet it returns. Shouldn't it stop processing logic after redirect()->route call?
Also this is purely REST application.
Why don't you use Laravel Middleware solution for your need ? You can link a middleware to your controller, checking if the current user is an administrator, and redirect if not :
//You Middleware Handle method
public function handle($request, Closure $next)
{
if ($this->auth->guest() || !($this->auth->user()->isAdmin))
{
return redirect('your/url')->with('error','no admin');;
}
return $next($request);
}
You can add on or multiple middleware for a controller in his construct method
//your controller
public function __construct(Guard $auth, Request $request){
$this->middleware('auth', ['except' => ['index', 'show']]); //here one 'auth' middleware
$this->middleware('admin', ['only' => ['index', 'show', 'create','store']]); //here the admin middleware
}
Notice the onlyand except parameters that allow or disallow the middleware for some controller methods
Check laravel documentation on Middleware for more information :)
No, your logic is slightly flawed. The return value you are sending back from checkAdminStatus() is simply being ignored and thrown away:
public function getAdminData()
{
// You don't have $redirectValue in your code, but imagine it
// is there. To actually redirect, you need to return this value
// from your controller method
$redirectValue = $this->checkAdminStatus();
Nothing is being done with that redirect. The only time something is being returned from your controller is happening on every single request. I would suggest something more like this:
public function getAdminData(UserManager $userManager)
{
if($userManager->isAdmin()) {
return response()->json(array('admin-data'));
}
return redirect()->route('forbidden-access');
}
I think this captures the spirit of your question: the only time anything is being returned here is if the user is an admin.
As an aside, you are returning JSON data in one case, and a redirect in another. This may not be a very good idea. My reasoning is because, normally, JSON data is returned in response to AJAX requests, which in my experience are seldom followed up with an actual redirect in the event of failure. (YMMV)
This is driving me crazy as I think I'm doing the right thing but its not working correctly.
I have a route with a middleware attached to it like below;
Route::get('post/{id}/{name}', 'BlogController#post')->name('blog-post')->middleware('blogGuard');
As you can see I've defined 2 route params
In my controller I have below;
public function post () {
return view('pages.blog.post');
}
With the middleware defined like this;
public function handle($request, Closure $next)
{
if (is_null($request->input('id')) ||
is_null($request->input('name'))) {
return redirect()->route('blog-home');
}
return $next($request);
}
Now if I click on a link like so; http://blog.example.co.uk/post/153/firstpost the middleware should not fire correct?
This is not the case. The middleware executes and I'm redirected. But if I remove the middleware then I'm able to access the page.
Any help appreciated.
If you are trying to access route parameters you probably want to explicitly get them from the route.
$request->route('id'); // pulls the $route->parameter('id');
$request->route('name'); // pulls the $route->parameter('name');
$request->id will check the request inputs before falling back to returning a route parameter.
$request->input('id') will only check the input sources for the request and not the route params.
If you use $request->id expecting to get the route param 'id', one could break your logic by passing id=anythinghere to the querystring or adding a 'id' var to a post request.
Try this
if (!$request->id ||
!$request->name)