【问题标题】:How do you use Plack::Middleware::Session with a Starman Server?您如何将 Plack::Middleware::Session 与 Starman 服务器一起使用?
【发布时间】:2015-03-19 15:08:31
【问题描述】:

我有一个基于 Starman 的服务器 -

#!/usr/bin/perl
use strict;
use warnings;
use Data::Printer;
use Plack::Builder;

my $app = sub {
    my $env = shift;
    my $session = $env->{'psgix.session'};

    # Print environment variables
    p($env);

    return [
        200,
        [ 'Content-Type' => 'text/plain' ],
        [ "Hello, you've been here for ", $session->{counter}++, "th   time!" ],
    ];
};

my $default = sub {
    my $env = shift;
    p($env);
    return [
        '200', [ 'Content-Type' => 'text/html' ],
        ["Welcome to default page"],
    ];
};

builder {
    mount "/validate" => builder {
        enable "Middleware::Authentication"
        enable "Session";
        $app;
    };
    mount "/" => builder { $default };
};

我自己的中间件“身份验证”对用户进行身份验证并返回会话信息(到期时间、会话密钥等)用于会话管理,那么我如何在会话中间件中使用这些信息?

【问题讨论】:

    标签: perl authentication plack starman


    【解决方案1】:

    如果我理解正确,您的问题仅出在中间件的顺序上。在Auth 之前启用Session

    检查以下,使用文件存储,会话持久存储。试试看,重新启动您的Starman,计数器将重新加载。 (我使用 inline 中间件代替您的 Authentication。)

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use Data::Printer;
    use Plack::Builder;
    
    my $app = sub {
        my $env = shift;
        my $session = $env->{'psgix.session'};
        return [
            200,
            [ 'Content-Type' => 'text/html' ],
            [
                "My app page is visited ",
                $session->{counter}++,
                "th times! Validation is done at:",
                $session->{mwaretime},
                q{<br><a href="/validate">go validate again</a> --- <a href="/">reload this page</a>}
            ],
        ];
    };
    
    my $validate = sub {
        my $env = shift;
        my $session = $env->{'psgix.session'};
        $session->{counter} = 0;
        return [
            '200', [ 'Content-Type' => 'text/html' ],
            [
                "Resetting the counter:",
                $session->{counter},
                 ". Time from middleware: ",
                $session->{mwaretime},
                q{<br> <a href="/validate">reload this page</a> --- <a href="/">go to index</a> }
            ],
        ];
    };
    
    builder {
        #the session will be stored persistently
        #enable the Session BEFORE your middleware
        enable 'Session', store => 'File';
    
        mount "/validate" => builder {
            #enable "Authentication";
            #following is same as an middleware
            enable sub {
                my $app = shift;
                return sub {
                    my $env = shift;
                    my $session = $env->{'psgix.session'};
                    $session->{mwaretime} = time();
                    $app->($env);
                };
            };
            #end of the middleware
            $validate;
        };
        mount "/" => $app 
    };
    

    【讨论】:

    • 感谢 jm666 的回复。我正在寻找中间件的序列化,即在从 Auth 中间件进行用户身份验证之后,它返回我想在 Session 中间件中使用来管理会话的会话 ID(令牌)、用户登录时间等。那么我如何将一个中间件的输出传递给另一个。这种方法可以吗?
    • @CodeQuestor 你能做的最好的事情,search metacpan 对于一些Plack::Middleware::Auth 模块,并检查它们如何使用会话中间件的来源。我不确定session ID,因为它是由会话中间件本身使用Plack::Session::State 生成的(您可以在其中传递自己的coderef,返回SID。)
    • 感谢 jm666 的指导,让我尝试更多。
    【解决方案2】:

    从您的问题中,很难准确说出您的要求是什么样的。但是,如果您想对会话管理进行如此多的控制,编写自己的中间件可能会更好。也就是说,有一些方法可以使Plack::Middleware::Session 适应某些场景。但他们中的大多数都或多或少地使用了未记录的功能。这意味着您必须熟悉源代码,并且这些功能可能会在以后的版本中更改或消失。

    如果您想提供自己的会话密钥,可以将自定义 SID 生成器和验证器传递给 Plack::Session::State

    enable 'Session',
        state => Plack::Session::State->new(
            sid_generator => $my_generator,
            sid_validator => $my_validator,
        );
    

    sid_generatordocumentation 基本上说“只需阅读源代码”。

    您还可以实现自己的Plack::Session::Store 后端。但在这种情况下,切换到自定义解决方案可能更有意义。

    关于cookie过期时间,您可以在$env-&gt;{'psgix.session.options'}中设置expires选项在创建新cookie之前

    $env->{'psgix.session.options'}{expires} = $my_expires;
    

    这不是超时,而是自 UNIX 纪元以来的以秒为单位的时间,或Cookie::Baker 接受的任何值。

    也许您应该重新考虑您的身份验证中间件是否真的必须生成会话密钥。就像@jm666 所说,您通常在身份验证之前运行会话中间件。然后您的身份验证代码可以访问所有会话信息。会话 ID 通常是会话管理的实现细节,不必涉及代码的其他部分。要更改过期时间,请参阅my answer to this question

    【讨论】:

    • 感谢您的回复 nwellnhof。实际上会话将按用户维护,并且用户必须在进入某个会话之前进行身份验证。会话密钥/令牌将与其他服务器共享,当用户向这些服务器发送一些命令时,该会话密钥/令牌将被验证。这就是我在身份验证中间件中生成会话密钥的原因。
    猜你喜欢
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 2016-02-08
    • 2018-06-02
    • 1970-01-01
    相关资源
    最近更新 更多