管理会话变量的方法

methodologies for managing session variables

我最近几天一直在阅读 (mysql) 触发器...具体来说,我想做的是找出更新用户信息的好方法。


案例使用与用户管理系统相关: 例如,admin 用户将 regular 用户更新为 manager,此用户 type 更改将在界面上 enable|disable 软件功能。

问题: 你不会知道这个用户 type 的变化,除非你查询数据库并重置例如 $_SESSION['user']['type'] 变量,或者用户登录|退出系统。


问题:有什么好的方法可以解决这个头痛的问题吗?

如果您的脚本使用 $_SESSION['user']['type'] 来了解用户的权限,我会更改它的值。 或者也许我不明白这个问题?

我认为最安全的方法,我会选择 "headache" 方法。

  1. 'regular' 用户 A 登录并打开会话 A1。
  2. 'admin' 用户将 A 升级为 'manager'。
  3. 目前,会话 A1 是一个有效会话,但它不会授予用户 'manager' 权限。
  4. 当用户 A 注销并重新登录到会话 A2 时,该会话现在将授予用户“管理员”的所有权限,从数据库中查找当前 'type'。

根据您的应用,可能会稍微贵一些的备选方案:

每次用户出示会话令牌时,使用数据库检查会话的有效性。如果该会话包含无效信息(即 'type' 不再匹配),则强制用户重新登录。


添加另一个备选方案:

不要使用 MYSQL 触发器,当应用程序调用者(管理员)更新用户 A 的 'type' 时,它还会调用您缓存会话的任何位置以及 ( a) 更新会话(不建议*)或 (b) 使会话无效并强制用户重新登录。


*请注意,所有这些解决方案都要求用户在获得新的 'manager' 权限后重新输入其凭据,然后才能访问 'manager stuff'。我认为这比在没有任何身份验证的情况下更新会话更安全。

一种替代方法是执行 ajax 请求,间隔一段时间,这将更新您的用户 $_SESSION。 如果你的 'type' 有任何变化,你可以做任何你想做的事,比如强制用户重新登录你的应用程序,或者除了更新 $_SESSION 信息什么都不做。 当然,您需要知道您是否真的需要在用户注销和下次登录之前获取此信息,并更新配置文件。

我不认为 mysql triggers would be ideal for this。为什么?因为您很可能最终会在 php 和 mysql 中得到部分逻辑。坚持使用一种技术是一件好事,因为以后 maintain/debug 为您和您的同事编写代码会更容易。

因此,在您的情况下,如果您希望用户角色的更改立即采取行动,您将不得不在每个脚本上加载用户角色 运行 或使用数据库中的某些标志注销用户,这将表示他的会话不再有效(或者您可以实现自己的 session_set_save_handler,将会话保存在文件中的某个位置,您可以在其中删除它以注销用户)。

这取决于您的需求,哪种解决方案更适合您的情况。

  • 如果您的角色逻辑很复杂并且它包含分配给一个用户的多个角色以及每个用户的额外权限assignments/excludes,那么这样做可能会更好检查一次用户登录,然后使用会话记住结果。
  • 如果检查每个脚本的权限 运行 不是问题,您可以去做。但请注意,出于安全原因,强制用户重新登录可能是一个好习惯。
  • 如果用户注销可能导致失去工作,您应该让用户注销[=33] =] 本身并在下次登录后应用新权限(您可以向用户显示一条消息,表明新权限正在等待登录生效)。

所以这真的取决于您的需要,选择是注销用户、立即授予他新权限还是等到下次登录更好。

我推荐的方法是将每个用户的 type 存储在数据库中。如果您决定将 type 存储为 session 变量,将会出现的问题是(除其他外):

  1. 一旦 session 过期,此信息将丢失。通常 session 持续 30 分钟,但您可以根据需要将其修改为任意时长。但是,如果您创建一个持续 1 个月的 session,那么有权访问该用户计算机的任何人都将登录到用户帐户 ,而无需使用任何密码

  2. 您将无法使用数据库提供的强大且高级的查询(例如 MySQL 使用 SQL)。如果将信息存储在 sessions 中,当然可以找到一种方法来逐一查找每个用户的信息,但为什么要重新发明轮子呢?从头开始开发数据库结构并不容易,所以我不建议这样做。

关于您对信息更新后访问数据库的担忧,我不会说此信息像您认为的那样令人担忧。让我们想象以下示例:

1)

如果用户当前是 经理 并加载了一个他可以执行强大操作的网站,然后他立即被降级为 普通 用户,然后将此信息保存在数据库中就可以了。如果用户试图使用他的权力(不再属于他),他将单击一个按钮,该按钮将向数据库发送请求以确认他的 type。数据库查询非常快,所以速度不是问题。我更关心从 session 变量获取信息的速度,而不是从数据库获取信息的速度。

2)

如果用户在页面上时是普通用户,而在页面上时他变成了管理员,那么刷新页面后,他就可以行使自己的权力。我的意思是,如果你使用 sessions 并且你想让页面自动获取信息,比如 AJAX 然后更新他在页面上的选项,那会比简单的刷新消耗更多的服务器功率。

给出一个简单的 SELECT * FROM myTable WHERE id = 4 在数据库上执行只需 1 毫秒。数据库专为提高速度而设计,这就是它们受到青睐的原因

然而,也许您无法访问数据库,这就是您寻找替代方案的原因?好吧,你是幸运的! MySQLi是一个只使用文件存储信息的数据库。它专为没有太多资源的用户设计,并且具有 MySQL 应有的许多功能。

由于每个用户都有 roletype,这意味着在您的应用程序中查看或编辑内容的能力与这个因素密切相关。这意味着您的会话变量应该具有的 2 个基本内容是 userIDuserType,您还应该将它们存储在数据库中

这些信息可以传递给 $_SESSION['user'],例如作为一个小数组,您的数组键可以是 userIDuserType 的值。

$_SESSION['user']=array($userID => $userType);

用户登录后,您的初始值将存储到 session。为了让您的应用程序 知道 userA 可以在您的应用程序中查看或编辑什么,您基本上 运行 在脚本中与 userType userA 有。但是要实现您想要的效果,您基本上需要在应用程序的每个 VIEW/PAGE 开头重新获取该信息。如果新 userType 已分配给 userA 只需显示一条消息,表明 he/she 将在 15 秒内自动注销(请花时间阅读消息本身)以使更改生效.当您的用户看到此消息时,您获取 he/she 可能拥有的当前会话数据并将其保存在数据库中,因为某些会话变量可能(或不)在 userType 的升级或降级中可用。通过将 userType 的比较放在应用程序每个 VIEW/PAGE 的开头,您可以避免用户可能丢失数据的麻烦。

Question: Is there any good methodologies to solve this headache?

找到不这样做的充分理由!

虽然这听起来像是个玩笑,但我是认真的。你必须考虑:

  • 该功能的价值是多少?
  • 头疼的成本值得吗?
  • 该功能的风险是什么(不完整的工作/系统一致性)?
  • 要换系统内核吗?
  • 是否需要重新验证系统?
  • 还有其他非常棒的功能(系统改进)等待实现吗?

不愿意回答这些问题的人并不真正需要该功能。

寻找简单的替代方案:

  • 打电话给用户并要求注销。
  • 通过电子邮件通知用户。
  • 提供电子邮件通知按钮。
  • 更改权限后自动发送电子邮件通知。

这不是懒惰。只关注真正的价值。

我认为将您的会话存储到像 Redis 这样的缓存机制中会给您带来更多优势。它比在数据库中存储会话数据轻量级。您可以非常轻松地创建集群。单击 here 查看示例实现。

所以一旦用户"type"改变,你可以加载redis数据缓存并根据你的意愿更新它。