与许多Web应用程序一样,当我的用户登录我的站点时,我设置了几个控制访问站点功能权限的会话变量。
每当用户执行可能导致更改这些权限的操作时,我都会将会话变量更新为正常处理流程的一部分。
但有时需要根据其他用户的操作更新用户的会话。例如,主持人升级用户的权限。主持人无权访问用户的会话空间,因此无法为受影响的用户运行正常的更新功能。
我考虑了一些强制更新到另一个用户会话的方法,但它们都有缺点:
那么我有什么遗漏的吗?我在寻找一个不存在的魔法子弹吗?
(请注意,我已使用CodeIgniter对此进行了标记,并参考了CI特定的技术细节,因为这就是我正在使用的内容。也就是说,这不是特定于CI的(甚至是特定于PHP的) )问题。)
感谢您的帮助!
答案 0 :(得分:3)
嗯,一个选项是设置“ACL版本”号(适用于所有用户或每个用户)。然后在初始化会话时(好吧,当您调用session_start()
时)检查存储的版本是否与会话的版本匹配。如果没有,请刷新ACL。
另一种稍微不同的方法是在会话表中添加一列(“status”或“dirty”等)。然后,只需将该状态更新为1
,而不是终止会话。然后在加载会话时,检查该标志以查看它是否为1.如果是,请重新加载会话中的缓存数据并将其设置为0.如果不是,请继续...
至于更新另一个用户的会话,我不会这样做...如果会话由PHP管理,那么你需要终止当前会话并启动你想要修改的会话。这只是问问题......(你需要这样做,因为PHP的机制不使用序列化。)。
至于删除会话,我不担心全表扫描。除非你有TON用户一直在更新权限,否则不重要。数据丢失是一个重要的问题,所以那个想法的缺点......
至于其他两个选项,我认为你的头上钉了一针,所以我没有别的东西可以提供给他们......
答案 1 :(得分:2)
虽然我的方法并不完全适用于Code Igniter,但我会采取刺激措施。
我过去解决这个问题的方法是使用构造函数创建一个User对象模型,该构造函数从存储凭据的数据库主键中获取UserID。我将编写一个静态登录方法来检查登录凭据,然后实例化并返回一个用户实例,如果登录对某行是正确的,然后设置会话。
到目前为止这么好,对吗?因此,您的所有权限,访问级别等都存储在数据库中。就像使用登录方法一样,我们可以使用刷新方法重新实例化对象,从已经获得的主键中重新获取数据库。
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);
}
}
使用此模型,每当我在会话中对可能需要时间敏感权限的用户执行操作时,我都可以在会话中为用户对象调用refresh。假设我们有一个控制器功能来访问受限制的表单。
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
}
}
因此,如果您已经为管理员编写了例程,他们需要做的就是在数据库中设置用户的权限,当刷新方法在特定的时间敏感函数上运行时,该数据将被放入用户会话。因此,您不一定要更新另一个用户的会话,您只需确定哪些操作按时间顺序敏感,它们需要最新权限并将该命令发送给会话中的用户对象。
这对我来说已经证明非常有效,因为重建只需要在需要最新权限的操作上执行。同样,我不确定它在CI和您的个人应用程序中是否有用,但我想我会分享。我假设你已经完成了所有必要的会话安全措施并开始了会话 - 像CI这样的大多数框架都会通过他们的本地方式为你处理这个问题。
答案 2 :(得分:1)
在会话表中添加一个可以保存用户对象主键的列。在登录时设置它,稍后使用它来更新会话。
编辑:如果您不想扩展会话表,请创建一个其他查找表,其中包含用户对象ID和会话密钥链接。
答案 3 :(得分:0)
如果您将会话存储为本机php会话,我倾向于不管它,并允许他们获得某种通知,他们需要登录/注销以刷新设置。我也有会话数据存储在数据库中的站点,然后更简单地写入新设置。