My app is PHP / CodeIgniter / TankAuth.
I have in my database an account balance of sorts, and I want to display this account balance on my app's pages. So I've got in all nicely working, holding the balance in the session data.
The balance only changes on login, under certain conditions. So in the tank_auth components, there is a controller, a library etc. The flow is that the Auth controller login calls on the Tank_auth library login function, where the session is created, and then calls on the model to update the login info (IP address, last login etc.) That's all out the box.
So I've extended the session aspects in the library, adding my own user data 'account_balance'. which is fine, but the problem is when the balance changes, my session data is "behind", and I'm really struggling to work out how to update it.
First attempt is to simply try and update the session information after I've updated my database, in the users model (the stock standard Tank_Auth model). It doesn't work, giving me an error.
After some experimenting get this, I realise that I don't understand what this is about. :
echo $this->session->userdata('ip_address'); //works fine - no errors
echo $this->ci->session->userdata('ip_address'); //fail
The Tank_auth modules (library, controllers, models, etc) sometimes refer to ci->sessions and sometimes not, but it uses both.
In the class constructors, it also uses:
$this->ci =& get_instance(); //in the library
$ci =& get_instance(); //in the model
I'm getting 2 errors :
Message: Undefined property: Auth::$ci
Trying to get property of non-object
I was under the impression that one would use CI sessions, because it has some nice features, or not if one doesn't want them. But using both.....?
What am I missing?
Thanks in advance.
//if you are using get_instance() in codeigniter then user following syntax to write code:
$ci =& get_instance();
echo $ci->session->userdata("ip_address");
Related
I am new to laravel. I am trying to implement email verification on my laravel6 project.
On my project, there're three user types named 'user' 'vendor' and 'admin'. I have prepared separate directories for each user type in 'Controllers' and each of them has their own Auth files (e.g. Directory 'App/Http/Controllers/Vendor/Auth' has its own VerificationController.php, etc). So far, I've successfully implemented registration and login/logout function for each type with separate table in my DB.
A issue popped up when I tried to implement email verification. When I tried to access to a page where email verification is required, 'Auth\VerificationController#show' method seemed to be called regardless of the user type.
I went over laravel source code and learned that within the process, router calls Illuminate/Routing/Router->emailVerification() method. And the emailVerification() method routes to 'Auth\VerificationController#show' regardless of the user type.
What I wanted to do is to route depending on user type (e.g. if 'vendor' tries to login, I want to call 'Vendor\Auth\VerificationController#show').
I don't come up with any idea how to do for that. Can anyone please give me any advice?
Illuminate\Routing\Router class
public function emailVerification()
{
$this->get('email/verify', 'Auth\VerificationController#show')->name('verification.notice');
$this->get('email/verify/{id}/{hash}', 'Auth\VerificationController#verify')->name('verification.verify');
$this->post('email/resend', 'Auth\VerificationController#resend')->name('verification.resend');
}
Thank you in advance.
I've been using your advice and View::sharing all of my important data to all views. However, there is one issue I have encountered.
This code:
if(!Auth::guest()){
$user=Auth::user()->id;
}
else $user=0;
$temp=DB::select('query');
View::share('cartnumber', count($temp));
View::share('cartitems', $temp);
doesn't work when put in AppServiceProvider. Or better, it always sets $user=0, even if I am logged in. I thought it is because AppServiceProvider's boot function executes before the site checks if someone is logged in.
I then tried to use a BaseController with a construct function but that doesn't work either. The only solution that seems to work correctly is putting the code in every single Controller for every view! That actually works, which kind of confirms my theory.
But is there anywhere I can put this code without having to copy/paste it in every single Controller? Thanks in advance!
You'd likely want to put this code later in the request life cycle to guarantee an auth user because as others have mentioned middleware/session code has not occured during this part of the framework booting up. You could use a service class to call in all your controllers to avoid the copy pasting. Or If you'd like to achieve this using code in your service provider you could use a View Composer instead of a share this allows you to define a callback/or class that will be called right before the view is returned
view()->composer(['/uri-that-needs-data'], function ($view) {
if (Auth::check()) {
$cart = DB::query(...)->get();
$view->with('cartitems', $cart);
}
});
Check out https://laravel.com/docs/5.7/views#view-composers for more details.
Auth::user() will be empty until the session middleware has run.
The reason you can't access the user inside your service provider is because that code is run during the "bootstrapping" phase of the application lifecycle, when it's doing things like loading filesystem or cache drivers, long before the request is sent through response handlers (including middleware).
Once the application has been bootstrapped and all service providers
have been registered, the Request will be handed off to the router
for dispatching. The router will dispatch the request to a route or
controller, as well as run any route specific middleware.
Source: https://laravel.com/docs/5.7/lifecycle
If you don't want to copy/paste that code everywhere, then one place to put it is in custom route middleware. You can list it after the auth middleware to guarantee a logged-in user.
Edit: View composers are another really good option, as suggested by #surgiie. The reason these can be set up inside a service provider (unlike your example) is because the view composer registers a callback, but doesn't execute it until a much later stage in the application lifecycle.
I'm trying to code an SSO between Joomla and my CakePHP (1.3) app. Users should be able to log into Joomla, click a link to go to the CakePHP app and be logged in with the same user.
In my users_controller, I have an action called 'joomlalogin()' where I read the Joomla session variables, check to see whether the joomla user already exists in my CakePHP app, create the user if not. This all works.
The issue is that I can't seem to manually log the user in using Auth->login(). I tried passing a full user, tried passing the user_id. The function returns 'true' but as soon as I go to a next page, the login seems to have failed. Here's one version of the code:
$existing_user= $this->User->find('first', array('conditions' => array('User.joomla_userid' => $joomla_user->id)));
if ($existing_user && $this->Auth->login($existing_user)) {
$this->Session->setFlash('You have successfully logged in.');
//debug($this->Auth);
$this->redirect('/users');
}
The flash message appears, the redirect happens but it immediately gets redirected to the (regular non-sso) login form because the '/users' is not allowed for anonymous users.
Why is Auth->login() returning 'true' if the user is not really logged in. When I look at Auth->User(), it contains the correct user data, everything indicates the user is logged in until the redirect happens. Any idea what could be the cause of this or what I am doing wrong?
I was having the same issue. Turns out the system clock running on my server VM was incorrect. I ran this command to update it.
ntpdate time.windows.com
Note that this doesn't fix the underlying problem, which is that VM's have trouble keeping accurate time due to the nature of clock cycles being halted and suspended. Talk to your server administrator for a more permanent solution. Cheers to #Olivier for the tip
Check that sessions are enabled for all controllers you want to carry across user information; It's handy to put it in AppController, usually.
For example:
class AppController extends Controller {
public $helpers = array('Html', 'Form');
public $components = array('Auth', 'RequestHandler', 'Session', 'Security');
}
I sort of found the cause. The issue had something to do with the inclusion of the Joomla files (to access the Joomla session data & user). If I try to log the user in using a function where these files are not included, it does work. Some of the code that screwed it up was:
require_once (JPATH_BASE . DS . 'includes' . DS . 'defines.php');
require_once (JPATH_BASE . DS . 'includes' . DS . 'framework.php');
$joomla_mainframe = JFactory::getApplication('site');
$joomla_mainframe->initialise();
$joomla_session =& JFactory::getSession();
$joomla_user = $joomla_session->get('user');
Because of european privacy law being harsly applied in the Netherlands and to keep my company's site user friendly without nagging the users with questions if it's okay to store a cookie on their computer that allows me to access their client data.
What I need is a way to "overwrite" the native php sessions class so that at the point where the native class requests the cookie that stores the phpsessid, that I can place my own code there that checks the browsers fingerprint and matches that to a session id which I can use to return the normal working of the native class.
My idea is:
table sess_fingerprints
Fields: fingerprint - phpsessid
function getsessionid()
{
$result = $this->db->query("SELECT phpsessid
FROM `sessiondatabase`.`sess_fingerprints`
WHERE `sess_fingerprints`.`fingerprint` = '$userfingerprint'");
if($result->num_rows() != 0)
{
return $result->row->phpsessid;
}
}
and at that point the native php session code just works as it would normally do.
So, my question is: is it possible to overwrite only the "cookie" part of the phpsession class? if so, how? because I haven't found that yet.
I'm aware of being able to pass along the session variable via urls etc, but that's not secure enough for my web applications.
PHP provides support for custom session handlers:
http://php.net/manual/en/session.customhandler.php
I think I have found the solution to my problem.
I'm going to override the functions related to cookies by using http://php.net/manual/en/function.override-function.php
Thank you all for thinking along.
The idea is to catch any access to controller's functions and, if we are authenticated, rout as normal and, if not, show the login form.
The question is, is _remap function the best place to check for access to controller's functions and how to pass routing back to CI in case we are authenticated?
_remap isn't necessary for this. You could use it, but you don't need to.
Check for access in the __construct() method of the controller. You can get the current method via $this->router->fetch_method() and authenticate against that.
Better yet, have all your controller that need this extend a base controller (aka "MY_Controller"). You can write an Auth_Controller and do the auth check in the __construct() there. You can get the current class via $this->router->fetch_class(), as well as the method, just make sure your controllers that need this extend Auth_Controller instead of the usual CI_Controller.
If they shouldn't have access, just redirect them where they need to go or show an error.
make a library called Authentication and check about your method in this
you can get method and class name by this
$class = $this->CI->router->class;
$method = $this->CI->router->method;
and to check this authentication each time you have enabled the hooks from your config file, attach a post_controller_constructor hook to check authentication each time.