Setting session variables in Laravel 5.4 - php

I have a feeling this is a very dumb question and there's probably something really tiny I just overlooked, but I'm stumped anyway.
Currently, I have an app with a few pages that are protected through middleware. If the user does not meet the requirements of these middleware, they are redirected to a login page. Now after they log in, I want them to be sent back to the page they tried to visit.
I've tried numerous things to accomplish this, but none work. What I'm trying to do now is the following:
User attempts to access an admin page (for example /admin): PagesController#adminDashboard
When they access the overview() method in the controller (same as index(), but for admins), a session variable is set containing the url they tried to visit (/admin)
The user is redirected to the login page and logs in (SessionsController#create and #store)
After logging in, they are redirected to the session variable with the intended URL
This is how I tried to do it:
PagesController
public function adminDashboard()
{
$intended = '/admin';
session('intended-url', $intended);
//dd(session('intended-url');
$schools = School::all();
$articles = Article::all();
$sights = Sight::all();
return view('admin', compact('sights', 'articles', 'schools'));
}
SessionsController
public function store()
{
/*
...
*/
$intendedURL = session('intended-url');
if($intendedURL != null)
{
return redirect($intendedURL);
}
else
{
return redirect()->home();
}
Using dd() a few times here and there, I found out that it doesn't even set the session variable at the very start (commented dd() in PagesController returns null).
I've tried doing this using Session::put(), Session::set(), using square brackets as in session(['intended-url', '/admin']), but none of it gives me the result I'm looking for :(
Does anyone have any advice on how to do this, or perhaps a different way of accomplishing the same goal, but more efficiently? Thank you!
EDIT: I don't think the default Laravel redirect to intended page will work here, since I rewrote most of the login system from scratch to suit some specific needs. Unless anyone knows how that redirect works behind the scenes and I can over-/rewrite it

If you are using the default auth system, you can use this to redirect users to the page they wanted to view:
return redirect()->intended('fallback/uri');

why u are not using middleware just make new middleware
php artisan make:middleware admin
and add this code of public function handle
if (!Auth::guest() && Auth::user()->admin) {
return $next($request);
}
return redirect('/')->with('warning', 'This Area only For Admin');
add this code in kernal on protected $routeMiddleware
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\admin::class,
];
make new column in users table
$table->boolean('admin')->default(false);
now you can use your construct function
public function __construct()
{
$this->middleware('admin');
}
Note:- where u add $this->middleware('admin'); all controller will be locked for users and guest only admin can use this controller

Related

How to unit test if the user is being redirected to login page if email not validated

I'm trying to write some unit tests for my code, I'm just learning how to write tests and I'm new to Laravel. Basically, I have a simple project, where the user should register and after validating their email, they are redirected to the landing page. In order to avoid some infinite redirects and bugs, I added a few lines of code that prevents the user to redirect himself to the landing page before verifying their email. So this is what I have in the controller file :
public function index(): View|RedirectResponse
{
if (auth()->user()->email_verified_at)
{
return view('landing.country', [
'countries' => Countries::all(),
]);
}
auth()->logout();
return redirect(route('home'));
}
So, If the user hasn't verified his email, if he attempts to view the blade only accessible to authenticated users, I'm logging him out and redirecting to the login page. Even though writing this was quite simple, I'm having a hard time coming up with a proper way to test this. How should I be able to approach testing this particular logout section? I have to test if the user attempts to enter auth only blade and check if he is being logged out and redirected to input page? Any help would be appreciated, currently I've been trying something like this in my test units :
public function test_if_user_is_logged_out()
{
User::factory()->create();
$user = User::first();
Auth::logout();
$response = $this->actingAs($user)->get(route('landing.worldwide'));
$response->assertRedirect(route('home'));
}
But obviously it doesn't work. I'd be forever thankful for any suggestions and help!
You could update your test to something like:
public function test_an_unverified_user_is_logged_out_and_redirected()
{
$user = User::factory()->unverified()->create();
$this->actingAs($user)
->get(route('landing.worldwide'))
->assertRedirect(route('home'));
$this->assertGuest();
}
unverified() is a method that is included with fresh installs of Laravel.
If you don't have unverified() in your UserFactory, you can simply change the user create call to be:
$user = User::factory()->create([
'email_verified_at' => null,
]);

Laravel intended always returns email/verify

I'm using Laravel 7.4, and I want to redirect the users to the page they came from after the login. I edited the file RedirectIfAuthenticated and added the redirect like:
return redirect()->intended(RouteServiceProvider::HOME);
But the problem is, it always redirected me to home. When I actually logged what the intended function returns, it always returns the url as website.com/email/verify. I'm 100% sure I don't redirect the users to that url, because I am logging in with an already verified user.
It might be some FW setup that I failed to notice, since I took over this project from another developer. I'll provide any more info if needed.
Check for middleware maybe you are redirecting unverified users to email/verify
Then in your LoginController create a protected function redirectTo() and return url()->previous();
Your code will look like this
protected function redirectTo()
{
return url()->previous();
}
Or
Also you can add $this->redirectTo = url()->previous() to your constructor
like this
public function __construct()
{
$this->redirectTo = url()->previous();
$this->middleware('guest')->except('logout');
}
Hope this helps
If you dump dd(session()->all()) of a so-called "intended" page, you will see the following:
As you can see, Laravel store user's previously intended page at url['intended'] array element. So to imitate this behavior manually, you have to set this value manually where needed. In this case it's LoginController:
public function showLoginForm()
{
session()->put('url.intended', url()->previous());
return view('admin.auth.login');
}
Now the original location has been stored, and later when the user log in, they will be redirected as declared in RedirectIfAuthenticated#handle:
return redirect()->intended(RouteServiceProvider::HOME);
But what if the user went to the /login page intentionally, or simply put, what if they refresh the page? url.intended will have the value of route('login'), then when user logged in, they will be redirected to login page and the infinite loop continues.
In that case, url.intended should not have any value. RouteServiceProvider::HOME value will be used as destination. There must be additional condition for that, let's say your site have login route named login:
public function showLoginForm()
{
if (($url()->previous() != route('login')) {
session()->put('url.intended', url()->previous());
}
return view('admin.auth.login');
}
Case anything unclear, you may want to have a look at similar question

Laravel loginUsingId doesn't seem to work

I need to manually login a user in Laravel 5.7 via Auth. Once I run Auth::loginUsingId($userId, true) I then relocate the user to his Account page.
The point of this is for a user coming through a token can be logged in into the website, without adding his credentials again.
I've tried anything I could find online, including moving the Session from MiddlewareGroup to Middleware, checking the Cookie name and some other things that didn't work.
My Controller looks something like this:
public function loginExternal(Request $request) {
$userId = $request->uid;
Auth::loginUsingId($userId, true);
redirect()->to('/account')->send();
}
and the route for it is pretty simple:
Route::get('/oneclick/{token}', 'Auth\AccountController#loginExternal')->middleware('signed')->name('oneclick');
I would expect the user to be logged in and taken to his account automatically. Now it just sends me to the login page.
What I noticed is that the loginUsingId() method generates a new session id only in this controller, but in other pages of the website, the website is using a different session, the same one (which should happen).
I need to mention that the user does get loggedin in the LoginExternal method. It just doesn't persist to the account page.
Any ideas?
In controller:
public function loginExternal($id) {
$user = User::find($id);
if($user){
\Auth::loginUsingId($id, true);
return redirect('/account');
} else {
return redirect('/')->with('error_message', 'No user found!');
}
}
In route file (web.php)
Route::get('/oneclick/{id}', 'Auth\AccountController#loginExternal')->name('oneclick');

How can we redirect a page to another if a session is not found using route in Laravel 5.3

I am using a session separately other than the default authentication sessions. If an user try to access my secured page, he should have the session set. If anyone without that session try to access means, they will be redirected to error page. I am using Laravel 5.3
The user can view the below two pages only if the session variable named 'secured_user' is set. Otherwise they will be redirect to the error page
Route::get('/secured-page1', 'ValidationController#CheckSecuredLogin_1');
Route::get('/secured-page2', 'ValidationController#CheckSecuredLogin_2');
The best option would be a policy.
You can create certain constrains and couple it with your models. Policies are especially suitable for changing your logic later on.
See here: Create Policy
Within you PagesPolicy, you can add this function:
public function before(User $user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
public function seeSecurePage(User $user)
{
// Your custom Code and session handling
if(session("secured_user")) return true;
return false;
}
and in your controller.
$user->can("seeSecurePage","Pages");
If "can" fails, it will automatically redirect to error 403.
P.S.: Another possibility are Gates
You should use Laravel Middlewares to achieve this, I think middlewares are made for the work you need:
First create a new middleware by running the artisan command:
php artisan make:middleware CheckSesison
Then the CheckSession would look like this:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckSession
{
public function handle($request, Closure $next)
{
if ($session_value != 'YOUR_DESIRED_VALUE') {
return redirect('home');
}
return $next($request);
}
}
Now in your routes file you can use laravel's route middleware() method to implement it like this:
Route::get('/secured-page1', 'ValidationController#CheckSecuredLogin_1')
->middleware(CheckSession::class);
Hope this helps!
In addition to the awnser above, you could also use middleware that's used on the routes and even group them if required. It is a simple, quick and clean solution. Inside the middelware you simple check if the session you require is there and depending on the result you take any action necessary.
Laravel middleware docs

Laravel Routes - Same route, different controllers

I want to add a functionality on my web app where users visit the same URL and get different pages depending if they are logged in or not. The way I'm doing this now is using a middleware to redirect logged in users to /home. But, I want to do something like facebook does..
When someone types http://facebook.com, it analyzes if the person is logged in, if they are, it shows their home, if they are not, it shows the registration page on the same URL (you can see that the address in the bar does not change)
I'm trying to use this code on my route:
Route::get('/', array('as'=>'home', 'uses'=> (Auth::check()) ? "usercontroller#home" : "homecontroller#index" ));
Found Here: https://stackoverflow.com/a/18896113/2724978
But it just shows the second controller method ("homecontroller#index") no matter if the user is logged in or not.
Is it just me or can't you just do as #AJReading has suggested and use an ordinary controller method to handle this?
Set up like so:
In your HomeController.php:
class HomeController extends Controller
{
/**
* Show a different view depending on whether or not the user is logged-in.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
if (Auth::check()) {
// logged-in
return view('home.index.authorised')->with('user', Auth::user());
} else {
// not logged-in
return view('home.index.guest');
}
}
}
Then create your alternate views e.g. resources/views/home/guest.blade.php
here is exactly what you want:
Route::get('/', function() {
$guest = Auth::guest();
if($guest)
{
$controller = $this->app->make('App\Http\Controllers\TaskController');
return $controller->callAction('guest', $parameters = array());
}
else
{
$controller = $this->app->make('App\Http\Controllers\TaskController');
return $controller->callAction('user', $parameters = array());
}
});
Just replace the names with yours.
Tested on: Laravel Framework version 5.1.35 (LTS).
Should be improved further by looking at the namespacing.
Did came up with a better solution using middleware - but didn't save it and can't recreate it now.
Answer derived from/based on:
Laravel single route point to different controller depending on slugs
http://laravel.io/forum/10-16-2014-l5-controller-does-not-exist

Categories