Welcome Guest, Not a member yet? Register   Sign In
How to restrict each user to it's own data?
#1

I have tables in my CI project where data of many users is stored and I need to make sure each user can only see his own data. So in each model call I had where condition written like this:
PHP Code:
$clients $this->clientsModel
    
->where('active'1)
    ->where('user_id'$_SESSION['user_id'])
    ->findAll(); 
To make sure no-one can access data not belonging to him/her by manipulating the post/get variables, I had to do that also for update queries:
PHP Code:
$this->clientsModel->where('user_id'$_SESSION['user_id'])->update($id,$data); 
Then I thought, why not insert that
PHP Code:
->where('user_id'$_SESSION['user_id']) 
part into the model constructor (or initialize() function) so that it is applied on every model call?
I did it by adding a function like this to the model:
PHP Code:
protected function initialize()
{
    $this->where('clients.user_id'$_SESSION['user_id']);

And was happy for a short while, until I noticed that if I have two calls to the same model in a row, the second call DOES NOT get that query part applied...
So, unless this is a bug, I do not have simple solution to my problem (and even if it is a bug - that would be a pretty damn serious bug  and I would be hesitant to use such solution after the fix).
What do you guys do with such problem? Any error-prone ways to deal with it?
==

Donatas G.
Reply
#2

QueryBuilder resets the received data so that it does not get into the next request.
Therefore, this is normal behavior and there is no error here.

The first thing that came to my mind was using model events.
https://codeigniter.com/user_guide/model...del-events
But maybe someone will offer a simpler solution.
Reply
#3

(06-20-2023, 05:33 PM)iRedds Wrote: QueryBuilder resets the received data so that it does not get into the next request.
Therefore, this is normal behavior and there is no error here.

That's a relief, and I see I have a lot to learn, thanks!

(06-20-2023, 05:33 PM)iRedds Wrote: The first thing that came to my mind was using model events.
https://codeigniter.com/user_guide/model...del-events
But maybe someone will offer a simpler solution.

And the solution you suggested seems to work fine. I have added this to my models:

PHP Code:
protected $allowCallbacks true;
protected 
$beforeFind = ['restrictToUser'];
protected 
$beforeInsert = ['restrictToUser'];
protected 
$beforeInsertBatch = ['restrictToUser'];
protected 
$beforeUpdate = ['restrictToUser'];
protected 
$beforeUpdateBatch = ['restrictToUser'];
protected 
$beforeDelete = ['restrictToUser'];

protected function 
restrictToUser(array $data)
{
 
$this->where('invoices.user_id'$_SESSION['user_id']);
 return 
$data;

==

Donatas G.
Reply
#4

I think there is no need to add an event for "insert"
Reply
#5

(This post was last modified: 06-21-2023, 12:21 AM by dgvirtual.)

(06-20-2023, 10:30 PM)iRedds Wrote: I think there is no need to add an event for "insert"
Yep, true. funny that it still works.
==

Donatas G.
Reply
#6

(This post was last modified: 06-21-2023, 01:18 AM by demyr.)

I display or hide things/pages in view (files). If the ids do not match my warning says: You're not allowed to see this content. Or I can easily hide buttons. This is the first check.

Additionally, I allow/disallow any possible attempt in Controller.
Reply
#7

(06-21-2023, 01:17 AM)demyr Wrote: I display or hide things/pages in view (files). If the ids do not match my warning says: You're not allowed to see this content. Or I can easily hide buttons. This is the first check.

Additionally, I allow/disallow any possible attempt in Controller.

Don't you find it complex to maintain such code? I was looking for solution that would make only the content created by the particular user accessible to him. And events are perfect for that. If a user tries to see a piece of content that is not his, he gets a 404 page (I do not differentiate between content that should be accesible and content that is not there). Of course, your use case may be different.
==

Donatas G.
Reply
#8

I have also discovered that the event does not work well on $beforeUpdateBatch. So, the corrected version is like this:

PHP Code:
protected $allowCallbacks true;
protected 
$beforeFind = ['restrictToUser'];
protected 
$beforeUpdate = ['restrictToUser'];
protected 
$beforeDelete = ['restrictToUser'];

protected function 
restrictToUser(array $data)
{
    
$this->where('invoices.user_id'$_SESSION['user_id']);
    return 
$data;

==

Donatas G.
Reply
#9

Batch update does not work with "where" method.
Reply
#10

(06-21-2023, 10:56 AM)dgvirtual Wrote:
(06-21-2023, 01:17 AM)demyr Wrote: I display or hide things/pages in view (files). If the ids do not match my warning says: You're not allowed to see this content. Or I can easily hide buttons. This is the first check.

Additionally, I allow/disallow any possible attempt in Controller.

Don't you find it complex to maintain such code? I was looking for solution that would make only the content created by the particular user accessible to him. And events are perfect for that. If a user tries to see a piece of content that is not his, he gets a 404 page (I do not differentiate between content that should be accesible and content that is not there). Of course, your use case may be different.

No, why? It is pretty easy. I have an id in the url, and there is another one, which is the session. If they don't match, then I don't show the content.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB