Laravel unexpected redirects ( 302 ) - php

I have started a new Laravel 5.2 project, using laravel new MyApp, and added authentication via php artisan make:auth. This is intended to be a members only website, where the first user is seeded, and creates the rest (no manual user creation/password reset/etc).
These are the routes I have currently defined:
Route::group(['middleware' => 'web'], function () {
// Authentication Routes...
Route::get( 'user/login', ['as' => 'user.login', 'uses' => 'Auth\AuthController#showLoginForm']);
Route::post('user/login', ['as' => 'user.doLogin', 'uses' => 'Auth\AuthController#login' ]);
Route::group(['middleware' => 'auth'], function() {
// Authenticated user routes
Route::get( '/', ['as'=>'home', 'uses'=> 'HomeController#index']);
Route::get( 'user/{uid?}', ['as' => 'user.profile', 'uses' => 'Auth\AuthController#profile' ]);
Route::get( 'user/logout', ['as' => 'user.logout', 'uses' => 'Auth\AuthController#logout' ]);
Route::get( '/user/add', ['as' => 'user.add', 'uses' => 'Auth\AuthController#showAddUser']);
[...]
});
});
I can login just fine, however I'm experiencing some very "funky" behavior - when I try to logout ( via the built-in logout method that was created via artisan ), the page does a 302 redirect to home, and I am still logged in.
What's more, while almost all pages (not listed here) work as expected, user.add also produces a 302 to the home page.
Do note the homepage is declared to the AuthController as $redirectTo, if that makes any difference
I found out about the redirects via the debugbar. Any idea on what to look for ?

I got the same issue and i solved it by adding the header with accept:'application/json'. And I think I checked the source code before which indicates that if you don't add this, it might redirect when you are using the auth middleware. But I am not sure if it is the case and I cannot recall where i found this.

After several hours of hair pulling, I have found my answer -- and it's silly.
The problem is that the route user.profile has a path user/{uid?} and it matches both user/logout and user/add as paths.
It being before the others, and not having a regex or similar, it handled the route.
I still don't know why a 302 was generated for that page, but found that moving it out of the AuthController and into the UserController (where it should be from the start) fixed the behavior.
Thus, my (amended and working) routes now look like so:
Route::group(['middleware' => 'web'], function () {
// Authentication Routes...
Route::get( 'user/login', ['as' => 'user.login', 'uses' => 'Auth\AuthController#showLoginForm']);
Route::post('user/login', ['as' => 'user.doLogin', 'uses' => 'Auth\AuthController#login' ]);
Route::group(['middleware' => 'auth'], function() {
// Authenticated user routes
Route::get( '/', ['as'=>'home', 'uses'=> 'HomeController#index']);
Route::get( '/home', ['as'=>'home', 'uses'=> 'HomeController#home']);
Route::get( 'user/logout', ['as' => 'user.logout', 'uses' => 'Auth\AuthController#logout' ]);
// *** Added /profile/ here to prevent matching with other routes ****
Route::get( 'user/profile/{uid?}', ['as' => 'user.profile', 'uses' => 'UserController#profile' ]);
Route::get( '/user/add', ['as' => 'user.add', 'uses' => 'UserController#showAddUser']);
[...]
});
});

I encountered an issue with 302 Redirects when posting ajax requests. The solution in this case was to remember to include the CSRF token.
See the Laravel 5.4 documents here: https://laravel.com/docs/5.4/csrf

For me it was guest middleware!
This middleware redirects user to homepage if authenticated.
You don't have to use it for Api requests. So I removed it and the problem solved.

May be default redirect page after logout is home and seems like you do not have home in your web route. Try the below code in your AuthController.php
use AuthenticatesAndRegistersUsers, ThrottlesLogins; // after this line
$redirectAfterLogout = 'login' // add this line
This will redirect you to login page after logout. You can change it to any route if you wish. I used login as an example.
OR
You can change after logout route in \vendor\laravel\framework\src\Illuminate\Foundation\Auth\AuthenticatesUsers.php
public function logout()
{
Auth::logout();
return redirect(property_exists($this, 'redirectAfterLogout') ? $this->redirectAfterLogout : 'login');
}
I changed the default route to login. If you don't have $redirectAfterLogout in your AuthController.php it will look here for redirect path. I don't suggest people to edit here, it's kind of hard coding.

I had this issue and it turned out I had a route:redirect inside my ajax controller.
which doesn't make sense because obviously we have to return ajax but I was returning a route!

I too experienced this issue in the login page which worked fine previously. So thought have a look at the directory permissions and it resulted the following:
drwxr-xr-x 7 user user 4096 Jun 27 2019 storage
So storage directory has 755 permission which means only the owner has write access, Since that directory owned by "user" others like laravel can't write into it.
Changing the directory to 777 with this cmd resolved my issue:
sudo chmod 777 -R PROJECT_PATH/storage
The right way,
Since making that directory world-writable isn't the right way, make that directory owned by apache and set 775 to storage.. and it worked again.
sudo chown -R user:www-data PROJECT_PATH/storage
sudo chmod 775 -R PROJECT_PATH/storage

I use a lot ajax (get & post) and with every response I update the token with session()->regenerate() on the server, then on the client side I update every token field with js.
But last week, I delete by mistake the one liner function to do that. So, suddenly the system starts to give a 302 response after the second call. It was so hard to find what was going on, because it works sometimes (firstime) and sometimes don't.
After I realize it was a token mismatch, I struggle a couple of days trying to find why, because the response don't point a token mismatch, just the 302 redirect.
Finally, I find the problem by dd() both tokens on the tokensMatch() function. I don't know why it won't trigger a TokenMismatch.
I hope this anecdote help you.

If your website doesn't use HTTPS you have to define the following attribute in your .env
SESSION_SAME_SITE=Strict
Note: this precaution applied by some browsers to prevent exploit website's users

For me it was this in my controller:
public function __construct()
{
$this->middleware('admin');
}

For me it was config/session.php
I changed some values there for production app like path, secure, same_site
But on local due to http://localhost, Secure session was failing to create any cookies.
That's why Authenticate middleware redirecting to login page with status 302

I have modified my login route with adding as parameter to it and it worked for me.
Route::get('login', ['as' => 'login', 'uses' => 'loginController#index']);

As for me encountered 302 status during saving and what fixed that was inserting
Accept: application/json on ajax header, because i hava a script inside the php file.
$.ajax({
url:'{{route('fetchMunCit')}}' +'/'+id,
type:'GET',
dataType:'json',
Accept: application/json
success:function(response)

In case somebody is experiencing this.
My case was that the APP_URL value is different from the actual URL hence I was getting 302 error.

Related

Laravel 5.3 - Authentication is broken

About a year ago we took over an existing Laravel 5.1 site and upgraded to 5.3 - We recently became aware that an admin panel that was part of the old site no longer works (or unable to authenticate).
The original routes file contains the following:
//Login
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
//Admin
//Dashboard
Route::group(array('prefix' => 'admin', 'middleware' => 'auth'), function() {
//Dashboard
Route::get('/webadmin', array('as' => 'dashboard', 'uses' => 'Admin\DashboardController#index'));
});
Which after the upgrade stopped working as I understand the Route::controllers method was depreciated. We changed it to the following as I understand that was the replacement:
//Login
Route::resource('password','Auth\PasswordController');
Route::resource('auth','Auth\LoginController');
//Admin
//Dashboard
Route::group(array('prefix' => 'admin', 'middleware' => 'auth'), function() {
//Dashboard
Route::get('/webadmin', array('as' => 'dashboard', 'uses' => 'Admin\DashboardController#index'));
});
However, when we access the sites admin panel by example.com/admin/webadmin we are automatically redirect to example.com/login which then displays the dreadful NotFoundHttpException in compiled.php
This leads me to believe that the authentication middleware is not registered correctly. I am not sure what the correctly route is to take so will gladly appreciate any assistance :)
The redirect is happening because your not being authenticated and you are redirected to login route because the unauthenticated method in the app\Exceptions\Handler class redirects the user to /login using something like this:
return redirect()->guest('login');
So, you've to either create a /login route or change the above line to this:
return redirect()->guest('auth');
This should work and your AuthController::index method should show the login form because this will hit the index method in your AuthController because it's a resource controller.

Laravel 5.1 - Overloaded routes

I have a homegrown, Laravel 5.1 base application on top of which I build specific applications. The base application uses a named route for login, naturally called "login", which listens for GET /login.
In one of my specific applications, I attempted to overload that route to send the requests to a different controller. It seemed to work for a while, but then it started going to the base application's controller again. I'm sure I changed something to break it, but the problem is that I can't figure out how to fix it again.
My base application routes are all defined in app/Http/Routes/core.php. The relevant route:
Route::get('login', [
'as' => 'login',
'uses' => '\MyVendor\Core\Http\Controllers\AuthController#getLogin'
]);
My specific application routes are defined in app/Http/Routes/app1.php. The relevant route:
Route::get('login', [
'as' => 'login',
'uses' => 'App1\AuthController#getLogin'
]);
App2 and App3 are defined similarly. My app/Http/routes.php adds these routes like this:
require 'Routes/core.php';
Route::group(['domain' => 'app1.com'], function() {
require 'Routes/app1.php';
});
Route::group(['domain' => 'app2.com', function() {
require 'Routes/app2.php';
});
Route::group(['domain' => 'app3.com', function() {
require 'Routes/app3.php';
});
The problem I am seeing is that visiting app1.com/login, app2.com/login, and app3.com/login all result in the execution of \MyVendor\Core\Http\Controllers\AuthController#getLogin rather than App1\AuthController#getLogin.
EDIT: I have changed the problem description since I was describing it incorrectly as a problem with calls to route('login').
The index of the routes in Laravel follows a "$domain$uri" format, therefore routes with a domain won't overwrite those without. A fallback route without a domain should be declared after the domain group, so it is later in the route collection and won't match before a route with a matching domain.
"the most recent definition for a route is the effective route"
This is not a bug, this is the expected behaviour, a simple example would be setting a variable to value 1 then setting it to value 2, of course the (most) recent value takes place.

What is the best way to restrict any routes in Laravel 5.0?

I want to restrict some routes of my application and only allow that to only my authenticated user.
I tried check using the auth:check() function but it doesn't seem to work.
// Route Restriction
if (Auth::check()){
//Web Directory
Route::get('web-directory','WebDirectoryController#index');
}
When I got to mysite/web-directory I still get 404 Error - even if I'm currently log-in.
What is the best way to restrict any routes in Laravel 5.0 ?
All right, so I figured out the solution to my own question.
I restrict my routes by doing this
// Route group
$router->group(['middleware' => 'auth'], function() {
//Web Directory
Route::get('web-directory','WebDirectoryController#index');
}
Now, I can go to my route fine, and 404 Error will only kick in when the user is not yet log-in.
I hope this help someone.
This can be achieved by restricting routes individually too:
Route::get('web-directory', [
'middleware' => 'auth',
'uses' => 'WebDirectoryController#index'
]);

Laravel route to same depth

I have a site in a subfolder, example.com/mysite. I have a route there, login, which is accessed via example.com/mysite/login. This is the route:
Route::group(array('domain' => 'example.com'), function()
{
Route::get('/', function()
{
return Redirect::to('login');
});
Route::get('/login/', array('as' => 'login', 'uses' => 'AccountController#login'));
})
The problem is, when I have a link in my view like so:
<a href='{{{ route('login') }}}'>Login page</a>
It displays the path example.com/login instead of example.com/mysite/login. It think this has something to do with the domain group, but I don't know how to tell it to keep the current subdirectory. I've tried changing the domain to example.com/mysite in the group command, but that just causes an error. The redirection to login works, but how do I get the correct link in the view?
Turns out, this is because when it generates the route, it uses the domain provided in the group instead of getting it from the url. It can be overriden though, by specifying an empty domain in the individual route match, like so:
Route::get('/login/', array('as' => 'login', 'uses' => 'AccountController#login', 'domain' => ''));
This will allow it to ignore the domain specified in the group function. Unfortunately, from what I can tell, you need to do this for all of them.
Your routes do not follow a relative path. Even if you are in example.com/mysite, your route is made within the example.com domain.
Your redirect redirects you to example.com/login.
This is where your route is. Your redirect is redirecting to 'login'.
You named your route vendor_login. Therefore within the view, you have to write <a href='{{{ route('vendor_login') }}}'> to access your correct route.
Still, going to example.com/mysite/login will not show you your login page. It is available via example.com/login.
If you want to be available via example.com/mysite/login, use the following code.
Route::group(array('domain' => 'example.com'), function()
{
Route::get('/', function()
{
return Redirect::route('vendor_login');
});
Route::group(array('prefix' => 'mysite'), function()
{
Route::get('/login/', array('as' => 'vendor_login', 'uses' => 'AccountController#login'));
});
});
The difference here is that the login route is now placed within a group that uses the 'mysite' prefix. In this case, your login route is available via example.com/mysite/login.
The redirect is changed from Redirect::to('login') (which redirected to example.com/login, to Redirect::route('vendor_login') which redirects to the named route vendor_login, independent of its path.
EDIT:
Routes are absolute. If you want to make a link that is relative to the same depth, in your view just do Login. But this is not recommended. In that case you can not show the same view/link from routes with a different depth. Instead use named routes (as you did) which give you the most flexibility. Just put in your view the correct name vendor_login and change your Redirect::to to Redirect::route('vendor_login')
Hope this helps

Laravel 3.x Route issue: page not found even with the route set

I got an annoying problem with a route, for a section of a CMS that I'm developing.
I got routes for all the sections, "products", for example:
Route::get('admin/products', array('as' => 'admin/products', 'uses'=> 'admin.products#index'));
Route::get('admin/products/create', array('as' => 'admin/products/create', 'uses'=> 'admin.products#create'));
Route::get('admin/products/edit/(:num)', array('as' => 'admin/products/edit', 'uses'=> 'admin.products#edit'));
Route::get('admin/products/delete/(:num)', array('as' => 'admin/products/delete', 'uses'=> 'admin.products#delete'));
.. and the related files, like the products controller, the product model and the views.
Everything was doing well until I decided to create a new section, "users". I used the same approach as "products", creating the routes and the other files. In fact I just copied and paste the files, making the changes when needed -- pretty straightforward. By accessing "admin/users" and "admin/users/create", it works as expected. But I can't access "/users/edit/1" and "/users/delete/1". I thought it would be a route problem, but when I tested the route file, I got a 404 even before reaching the route. Here's an example:
Route::get('admin/users/edit/(:num)', function()
{
return "Holy Hell.";
});
"Holy Hell" is never printed into the screen.
Here's the config for "users":
Route::get('admin/users', array('as' => 'admin/users', 'uses'=> 'admin.users#index'));
Route::get('admin/users/edit/(:num)', array('as' => 'admin/users/edit/', 'uses'=> 'admin.users#edit'));
Route::get('admin/users/create', array('as' => 'admin/users/create', 'uses'=> 'admin.users#create'));
Route::get('admin/users/delete/(:num)', array('as' => 'admin/users/delete', 'uses'=> 'admin.users#delete'));
Things that I noticed / Checked:
The index view, where is the users list, got a "URL::to_route('admin/users/edit')" function. I have no errors on the screen, so Laravel understands that the route 'admin/users/edit' is set correctly.
I know that this is not a general problem, because the "edit" and "delete" methods for the other CMS sections have no issues.
The views for these methods are there. So this is not a "file not found" issue.
I wonder if I'm missing something really obvious here. Any ideas? If not, would anyone please tell me how to debug this?
Thank you very much.
EDIT: Heads up
Your routes are in a bad order. Reverse them. Routes are evaluated top down, so anything with admin/products in the route will route to admin.products#index and nothing else.
In your edit method, you need to have the id parameter defined.
Since you didn't post your controller, I'm assuming this is why, since the closure does not have the $id passed to it. Example:
// Required user id:
Route::get('admin/users/edit/(:num)', function($id)
{
return "Holy Hell.";
});
// Optional user id:
Route::get('admin/users/edit/(:num?)', function($id = null)
{
return "Holy Hell.";
});
In your case, you probably don't want the optional part unless you plan on spewing out an error (or redirecting on error).

Categories