How can I get credentials from the command line in a Mojolicious application?

I am developing a standalone Mojolcious application. In the code, I turn to the internal backend, where the user must provide some credentials.

I am currently using credentials inside the code as variables. It looks something like this:

$password = 'somthing'; 

I tried using the config plugin to store credentials there, but is there an option with Mojolicious to allow the user to provide their credentials when the daemon starts? Maybe like:

 perl myapp.pl daemon -user username -password password 

What is the best Mojolicious strategy to handle this use case?

+6
source share
1 answer

I will provide two solutions to this problem. One of them is quite simple, while the other uses several advanced methods.

Easy: use environment variables

You can simply pass environment variables to your application when it starts.

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

Mojolicious is Perl, so they end in %ENV . We can access them using $ENV{USERNAME} and $ENV{PASSWORD} . Usually these environment variables are all-caps. It would be wise to choose something specific to the application, so MYAPP_USERNAME is probably a better choice than USERNAME .

It's good that you can also install it in your shell environment, and then you never have to worry about it.

 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; 

In the above example, I created a helper that stores credentials for us, so it’s easy to access them. Of course, you could just use $ENV{USERNAME} in the whole code, but I think it's better to encapsulate it correctly.

If we curl localhost:3000 daemon, we get this result.

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

Optional: subclass daemon Command

All command line arguments are processed by Mojolicious :: Command .

You can create your own subclass of Mojolicious :: Command. This is described in the Mojolicious :: Cookbook . If you call it Mojolicious::Command::foo , you don’t even have to worry about adding another namespace for Mojo to search for commands.

But you can, unfortunately, not send several commands at the same time. So, create a subclass of credentials , and then it will not work.

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

So we need to do something else. A quick look at Mojolicious :: Command :: daemon tells us that it has only the run method, which is automatically called when this command is called. We want him to do something extra, so we will subclass this specific command.

 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; } 

We need to import getopt , which helps us read stuff from the command line. We store the username and password in the credentials helper, as in the first approach, because encapsulation is good.

Finally, we need to pass the original run method. This is done by calling $self->SUPER::run , which is the Perl way to call call run my superclass from which I inherited. It calls run in the pseudo-class SUPER:: . You can learn more about this at perlobj .

Now the actual application is almost the same.

 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; 

We run it as follows:

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

And if we curl localhost:3000 we get the same result.

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

Which of these methods you choose is up to you. I'm not sure which one I would prefer myself. Both have their merits.

Environment variables are easier to implement and more portable, but the code is not so clear. A subclass of the command can document itself when everything is done correctly, but perhaps your users would not expect anything other than daemon . This is also a lot more code.

+7
source

Source: https://habr.com/ru/post/1015181/


All Articles