如何在Mojolicious应用程序中从命令行获取凭据?

时间:2017-02-22 12:04:37

标签: perl mojolicious

我正在开发一个Mojolcious独立应用程序。在代码中,我正在联系内部后端,用户应在其中提供一些凭据。

目前我使用代码中的凭据作为变量。它看起来像是:

$password = 'somthing';

我尝试使用配置插件在那里存储凭据,但是Mojolicious是否有一个选项让用户在运行守护进程时提供他的凭据?也许像:

perl myapp.pl daemon -user username -password password

Mojolicious处理此用例的最佳策略是什么?

1 个答案:

答案 0 :(得分:8)

我将为这个问题提供两种解决方案。一个是相当容易的,而另一个使用一些先进的技术。

简单:使用环境变量

您可以在启动时将环境变量简单地传递给您的应用。

$ USERNAME=foo PASSWORD=bar perl app.pl daemon

Mojolicious是Perl,所以他们最终进入%ENV。我们可以使用$ENV{USERNAME}$ENV{PASSWORD}访问它们。通常,这些环境变量是全部大写的。选择特定于应用的内容是有意义的,因此MYAPP_USERNAME可能是比USERNAME更好的选择。

关于这一点的好处是你也可以在shell环境中设置它,然后你就不必担心它。

package MyApp;
use Mojolicious::Lite;
use Data::Printer;

helper( 
    credentials => sub { 
        state $credentials = { 
            username => $ENV{USERNAME}, 
            password => $ENV{PASSWORD}, 
        } 
    }
);

get '/' => sub {
    my $c = shift;
    $c->render( text => np $c->app->credentials );
};

app->start;

在上面的示例中,我创建了一个helper来保存我们的凭据,以便于访问它们。当然,您可以在整个代码中使用$ENV{USERNAME},但我相信正确封装它会更好。

如果我们curl localhost:3000守护进程,我们得到了这个输出。

$ curl localhost:3000
\ {
    password   "bar",
    username   "foo"
}

高级:继承daemon命令

命令行参数全部由Mojolicious::Command处理。

您可以创建自己的Mojolicious :: Command子类。这在Mojolicious::Cookbook中有记录。如果将其命名为Mojolicious::Command::foo,那么您甚至不必担心为Mojo添加另一个命名空间来查找命令。

但遗憾的是,你不能同时传递几个命令。因此,创建子类credentials然后执行此操作不起作用。

$ perl myapp.pl daemon credentials --username foo --password bar

所以我们需要做点别的事。快速查看Mojolicious::Command::daemon告诉我们它只有run方法,当调用该命令时会自动调用该方法。我们希望它做一些额外的事情,所以我们将该特定命令子类化。

package Mojolicious::Command::mydaemon;
use Mojo::Base 'Mojolicious::Command::daemon';
use Mojo::Util 'getopt';

sub run {
    my ( $self, @args ) = @_;

    getopt
        'u|username=s' => \my $username,
        'p|password=s' => \my $password;

    $self->app->credentials->{username} = $username;
    $self->app->credentials->{password} = $password;

    return $self->SUPER::run;
}

我们需要导入getopt,这有助于我们从命令行中读取内容。我们将用户名和密码存储在credentials帮助器中,就像第一种方法一样,因为封装很好。

最后,我们需要切换到原始的run方法。这是通过调用$self->SUPER::run完成的,这是Perl在我继承的我的超类上说调用run的方式。它在run伪类上调用SUPER::。您可以在perlobj中了解有关详情。

现在实际的应用程序几乎相同。

package MyApp;
use Mojolicious::Lite;
use Data::Printer;

helper(
    credentials => sub {
        state $credentials = { username => q{}, password => q{}, };
    }
);

get '/' => sub {
    my $c = shift;
    $c->render( text => np $c->app->credentials );
};

app->start;

我们这样运行:

$ perl code/scratch.pl mydaemon --username foo --password bar

如果我们curl localhost:3000得到相同的输出。

$ curl localhost:3000
\ {
    password   "bar",
    username   "foo"
}

您选择哪种方式取决于您。我不确定自己喜欢哪一个。两者都有优点。

环境变量更易于实现且更易于移植,但代码并不那么清晰。命令子类可以在正确完成时记录自己,但也许您的用户不会期望除daemon之外的其他内容。它还有更多的代码。