ETOOBUSY 🚀 minimal blogging for the impatient
Mojolicious::Plugin::Authentication example
TL;DR
A full example of using Mojolicious::Plugin::Authentication.
In previous post Mojolicious::Plugin::Authentication we took a look at… Mojolicious::Plugin::Authentication, a useful plugin for Mojolicious that can help us with managing authentication.
Here we take a look at a minimal and simplistic example for using it.
#!/usr/bin/env perl
use Mojolicious::Lite -signatures;
{
my %db = (
foo => {pass => 'FOO', name => 'Foo De Pois'},
bar => {pass => 'BAZ', name => 'Bar Auangle'},
);
sub load_account ($u) { return $db{$u} // undef }
sub validate ($u, $p) {
warn "user<$u> pass<$p>\n";
my $account = load_account($u) or return;
return $account->{pass} eq $p;
}
}
app->plugin(
Authentication => {
load_user => sub ($app, $uid) { load_account($uid) },
validate_user => sub ($c, $u, $p, $e) { validate($u, $p) ? $u : () },
}
);
app->hook(
before_render => sub ($c, $args) {
my $user = $c->is_user_authenticated ? $c->current_user : undef;
$c->stash(user => $user);
return $c;
}
);
get '/' => sub ($c) { $c->render(template => 'index') };
get '/login' => sub ($c) { $c->render(template => 'login') };
post '/login' => sub ($c) {
my $username = $c->param('username');
my $password = $c->param('password');
if ($c->authenticate($username, $password)) {
warn $c->is_user_authenticated ? 'YES' : 'NOT YET';
$c->redirect_to('/private');
}
else {
$c->redirect_to('login');
}
return;
};
get '/private' => sub ($c) {
return $c->redirect_to('/login') unless $c->is_user_authenticated;
return $c->render(template => 'private');
};
post '/logout' => sub ($c) {
$c->logout if $c->is_user_authenticated;
return $c->redirect_to('/');
};
app->start;
__DATA__
@@ layouts/layout.html.ep
<!DOCTYPE html>
<html lang="en">
<head><title>Whatevah</title></head>
<body>
<%= content %>
<hr>
%= t a => href => '/' => 'Home';
-
%= t a => href => '/login' => 'Login';
-
%= t a => href => '/private' => 'Private';
% if (defined $user) {
<form action="/logout" method="post"
style="display: inline"
>
-
<button type="submit"
style="background: none!important;
border: none;
padding: 0!important;
text-decoration: underline;
cursor: pointer;
color: #069;">Logout <%= $user->{name} %></button>
</form>
% }
</body>
</html>
@@ index.html.ep
% layout 'layout';
%= t h1 => 'Index - Free Access'
@@ private.html.ep
% layout 'layout';
%= t h1 => 'Private Stuff - Retricted Access'
Welcome <%= $user->{name} %>
@@ login.html.ep
% layout 'layout';
%= t h1 => 'login'
%= form_for '/login' => (method => 'post') => begin
username: <%= text_field 'username' %>
password: <%= password_field 'password' %>
%= submit_button 'log in'
%= end
The example should not require much explanation, as it leverages on the concepts and functions described in the previous post.
One thing that can be elaborated a bit is this part here:
app->hook(
before_render => sub ($c, $args) {
my $user = $c->is_user_authenticated ? $c->current_user : undef;
$c->stash(user => $user);
return $c;
}
);
In practice, we are always setting a user
key in the stash, putting
the information about the current user (via current_user()
) if
available, or nothing (undef
) otherwise. In this way, our templates
will have the data structure for the account at their disposal, e.g. to
show the user’s name etc.