开发者

Update another user's session - best practice?

As in many web applications, when my users log into my site, I set several session variables that control permissions for accessing site functionality.

Whenever a user undertakes an action that would result in a change to those permissions, I update the session variables as part of the normal processing flow.

But sometimes a user's session needs to be updated based on the actions of another user. For example, a moderator upgrades a user's permissions. The moderator does not have access to the user's session space, so the normal update functions cannot be run for the affected user.

I have considered a few ways of forcing an update to another user's session, but they all have drawbacks:

  • I could search for and delete their session from the sessions table, but this requires a full table scan (where sessdata like '%user_id%'), and it could cause the loss of content that the affected user may be engaged in generating.
  • I could force a session update periodically, such as when sess_time_to_update is triggered. But there is no guarantee that this will transpire prior to the user attempting to access the functionality for which the update is needed.
  • I could run a complete series of variable updates on every page load, but the whole point of maint开发者_开发百科aining a session is to avoid that overhead.
  • I could set a flag indicating the need for a session update, but that signal would have to be interrogated at every page execution, and in every controller. (I know that I could extend CI_Controller as MY_Controller, but I don't want to do that)
  • I'm already sending the user an email notifying them of the change in permission, and it's easy enough to make them click a session update link (or even log out and log back in). But there's no guarantee they are going to even read beyond the subject line, let alone actually click the link.

So is there anything I'm missing? Am I looking for a magic bullet that does not exist?

(Note that I've tagged this with CodeIgniter, and made reference to CI-specific technical details, because that's what I'm using. That said, this isn't a CI-specific (or even a PHP-specific) issue.)

Thanks for the help!


Well, one option would be to set an "ACL Version" number (either for all users, or for each user). Then when initializing the session (well, when you call session_start()) check to see if the stored version matches the session's version. If it doesn't, refresh the ACL.

Another slightly different way would be to add a column to the sessions table ("status" or "dirty", etc). Then, instead of killing the session, simply update that status to 1. Then when loading the session, check that flag to see if it's 1. If so, reload the cached data in the session and set it to 0. If not, continue on...

As far as updating another user's session, I wouldn't do that... If sessions are managed by PHP, then you'll need to kill the current session and start the one you want to modify. That's just asking for problems... (you need to do that, since PHP's mechanism does not use serialize.).

As far as deleting their session, I wouldn't worry about the full table scan. Unless you have a TON of users updating permissions all the time, it's not going to matter. The data loss is a significant concern, so that nicks that idea...

As far as the other 2 options, I think you hit the nail on the head, so I have nothing else to offer on them...


I'm going to take a stab, though my approach is not entirely applicable to Code Igniter.

The way I've solved this problem in the past is to make a User object model with a constructor that takes the UserID from the database primary key where the credentials are stored. I'll write a static login method that checks login credentials and then instantiates and returns an instance of user if the login is correct for a row and then sets the session.

So far so good, right? So all your permissions, access levels etc are stored in the database. Just like having a login method, we can have a refresh method that reinstantiates the object, re-fetching from the db off the already obtained primary key.

class User{
public function __construct($uid){
  //fetch from the db here
  $sql = 'SELECT FROM User_Table WHERE UserID = ?';
  $params = array($uid);
  //fetch and assign using your flavor of database access, I use PDO
  //set all your object properties for access, as well as user_id, something like 
  //$this->user_id = $result['UserID'];
}

public static function Login($uname, $pass){
  $sql = 'SELECT UserID FROM User WHERE Username = ? AND Password = ?';
  $params = array($uname, md5($pass));
  //again I'm going to employ pseudocode here, fetch according to your preferred system
  if(!empty($result)){
    $_SESSION['user'] = new User($result['UserID']);
  }else{
     //login failed!
     return false;   
  }
}

final public function _refresh(){
  //refresher method.  Since the controller sets all the object properties for access
  //reconstructing and assigning it refreshes these priveliges.
  $_SESSION['user'] = new User($this->user_id);
  }

}

Using this model, whenever I am performing an action with the user in the session that might potentially need time-sensitive permissions, I can call refresh on the user object all ready in the session. Let's say we have a controller function to access a restricted form.

function _topSecret(){
$_SESSION['user']->refresh();

if($_SESSION['user']->specific_permission_from_db){
  //Perform the special action, get the view, whatever.
}else{
  //redirect to an error page
}

}

So if you already have routines written for the admins, all they need to do is set the user's privileges in the database, and when the refresh method runs on the specific, time-sensitive functions, that data will be put in the session for the user. So you're not necessarily updating another user's session, you're just determining which actions are so chronologically sensitive they require the newest permissions and issuing that command to the user object in the session.

This has proven pretty efficient for me, since reconstructing need only be performed on actions that need the most up to date permissions. Again, I'm not sure how useful it may be in the context of CI and your individual application, but I figured I'd share. I'm assuming you've already done all the necessary session security measures and started the session - most frameworks like CI will handle this for you through their native means.


Add a column in the session table that can hold the primary key of the user object. Set it upon login and use it later to update the session.

Edit: If you don't want to extend the session table, make an additional lookup table where you have the user object id and the session key link.


If your're storing the session as a native php session I'd tend to leave it alone, and allow them to get some kind of notice that they need to login/out to refresh the setting. I've also had sites where the session data is stored in the db and then its much more trivial to just write the new setting in.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜