8

我正在编写一个需要相当短的会话到期时间(15 分钟)的 Catalyst 应用程序。我正在使用标准的 Catalyst 框架身份验证模块,因此用户数据存储在会话中——即,当您的会话到期时,您将被注销。

此应用程序的许多使用都需要超过 15 分钟才能完成,因此用户会经常提交表单,结果却发现他们的会话状态消失了,他们需要重新登录。

如果发生这种情况,我想保留原始表单提交,并且如果他们成功登录,则继续执行表单提交,就像会话没有过期一样。

我已经通过控制器中的 auto() 方法处理了身份验证内容——如果您请求一个需要身份验证的操作并且您当前没有登录,您将被重定向到 login() 方法,该方法显示登录表单,然后在提交后对其进行处理。当 auto 方法重定向到 login() 时,似乎应该可以存储请求和任何表单参数,然后如果 login() 成功,则将它们拉回来——但我不完全确定最好的以通用/标准/可重用的方式获取或存储此信息的方法。(我正在考虑将其存储在会话中,然后在将其拉出后将其删除;如果这看起来是个坏主意,那就另当别论了。)

是否有标准的“最佳实践”或食谱方法来做到这一点?

(一个皱纹:这些表格是通过 POST 提交的。)

4

5 回答 5

4

我不禁想到,在一个应用程序中规定 15 分钟的超时时间是一个根本性的缺陷,该应用程序通常需要 15 分钟以上的操作之间的时间。

尽管如此,我会考虑重写该Catalyst::Plugin::Session->delete_session方法,以便$c->request->body_parameters序列化并保存(可能是数据库)的任何内容以供以后恢复。您可能需要对 POST 参数进行一些基本检查,以确保它们是您所期望的。

同样,create_session需要负责将这些数据从数据库中拉出,并使其可用于原始表单操作。

这似乎是一个混乱的情况,我倾向于重复我的第一句话......

更新:

无论您使用delete_session还是auto,矛盾的问题仍然存在:您不能在会话中存储此信息,因为超时事件会破坏会话。您必须将它存储在更永久的地方,以便它在会话重新初始化时仍然存在。Catalyst::Plugin::Session本身正在使用Storable,您应该能够使用以下内容:

use Storable;
...
sub auto {
    ...
    unless (...) { #ie don't do this if processing the login action
        my $formitems = freeze $c->request->body_parameters;
        my $freezer = $rs->update_or_create(
              {user => $c->user, formitems => $formitems} );
        # Don't quote me on the exact syntax, I don't use DBIx::Class
    }
    ...
    my $formitems = $c->request->body_parameters
                  || thaw $rs->find({$user => $c->user})->formitems
                  || {} ;
    # use formitems instead of $c->request->body_parameters from here on in

基础表可能有(用户 CHAR(x)、formitems TEXT)或类似的。也许是一个时间戳,以便恢复任何太陈旧的东西。您可能还想存储您正在处理的操作,以确保检索到的表单项属于正确的表单。你比我更了解你的应用程序的问题。

于 2009-01-07T01:18:54.023 回答
2

我会将表单数据作为某种用户数据存储在模型中。

Catalyst::Plugin::Session::PerUser是这样做的一种方式(尽管有点老套)。我建议仅将会话插件用于身份验证并将所有状态信息存储在存储用户数据的模型中。

我完全同意 RET 的观点,即 15 分钟的限制在这种情况下似乎真的适得其反。

于 2009-01-07T04:07:56.273 回答
1

我在 CPAN 搜索完全不相关的东西时遇到了这个问题。

Catalyst::Plugin::Wizard声称可以完全满足您的需求。文档建议它可以重定向到登录页面,同时保留先前操作的状态。

注意:我没用过,所以不能保证它的有效性。

于 2009-01-12T23:38:13.890 回答
1

最后,我们最终在 auto() 中获取了待处理的请求(URL+参数),对其进行序列化和加密,并通过登录页面上的隐藏表单元素传递它。如果我们收到一个填充了隐藏元素的登录请求,我们会对其进行解密和反序列化,然后进行适当的重定向(确保通过标准的“这个用户可以做这件事”代码路径)。

于 2009-02-21T03:35:13.120 回答
0

您总是可以在客户端上安装一些 javascript,通过每隔几分钟发出一个小请求来防止会话过期。

或者,您可以让 AJAX 在发布表单之前检查活动会话,并在需要时向用户显示新的登录框。

于 2009-01-07T17:01:12.250 回答