In the [last installment][lastinstallment], we created
Jacquard::Schema::User
to describe a Jacquard user, and
used Jacquand::Model::KiokuDB
(and a helper script) to
persist User objects to storage. This time around, we're going to
create our [Catalyst][catalyst] app and hook up authentication.
So, first step: create the Catalyst application. The
catalyst.pl
helper makes this trivial:
$ catalyst.pl Jacquard::Web
created "Jacquard-Web"
created "Jacquard-Web/script"
created "Jacquard-Web/lib"
created "Jacquard-Web/root"
[ couple dozen more lines elided ]
Unfortunately, there's no easy way to tell it "I'm creating this Cat
app as a part of a bigger project" -- so after creating it, you have
to manually shuffle the files around to get them into the right
place. The Catalyst files also come with quite a bit of templated
stuff in them that we don't need (POD skeletons and the like), so
cleaning that up and getting the code into line with your personal
coding style should be done at this point. Once that's all done,
checkpointing into revision control is a good idea:
$ git ci -m"Create Catalyst application"
[03-catalyst 3c20771] Create Catalyst application
11 files changed, 300 insertions(+), 0 deletions(-)
create mode 100755 jacquard_web.psgi
create mode 100644 lib/Jacquard/Web.pm
create mode 100644 lib/Jacquard/Web/Controller/Root.pm
create mode 100644 root/favicon.ico
create mode 100644 root/static/images/btn_88x31_built.png
create mode 100755 script/jacquard_web_cgi.pl
create mode 100755 script/jacquard_web_create.pl
create mode 100755 script/jacquard_web_fastcgi.pl
create mode 100755 script/jacquard_web_server.pl
create mode 100755 script/jacquard_web_test.pl
Next, we're going to use [CatalystX::SimpleLogin][simplelogin] to add
authentication to the application, following the outline in
[the manual][simpleloginmanual]. First up, add a number of plugins to
the application (in lib/Jacquard/Web.pm
):
use Catalyst qw/
-Debug
ConfigLoader
+CatalystX::SimpleLogin
Authentication
Session
Session::Store::File
Session::State::Cookie
Static::Simple
/;
Create a default View class by running:
./script/jacquard_web_create.pl view TT TT
Then create the Catalyst Model class that will wrap
Jacquard::Model::KiokuDB
:
package Jacquard::Web::Model::KiokuDB;
use Moose;
use Jacquard::Model::KiokuDB;
BEGIN { extends qw(Catalyst::Model::KiokuDB) }
has '+model_args' => ( default => sub { { extra_args => { create => 1 }}});
has '+model_class' => ( default => 'Jacquard::Model::KiokuDB' );
__PACKAGE__->meta->make_immutable;
1;
We also need to add the configuration for these plugins to the
application config file:
---
name: Jacquard::Web
Model::KiokuDB:
dsn: dbi:SQLite:dbname=db/jacquard.db
Plugin::Authentication:
default:
credential:
class: Password
password_type: self_check
store:
class: Model::KiokuDB
model_name: kiokudb
Finally, we can add a method requiring authentication to the root
Controller (which is at
lib/Jacquard/Web/Controller/Root.pm
):
sub hello_user :Local :Does('NeedsLogin') {
my( $self , $c ) = @_;
my $name = $c->user->id;
$c->response->body( "Hello, $name!
" );
}
(Don't forget that you need to change the parent class of the
controller as well:
BEGIN { extends 'Catalyst::Controller::ActionRole' }
If things aren't working, make sure you didn't forget this.)
With all this in place, you should be able to start up the
application, by either running
./script/jacquard_web_server.pl
or, if you want to get
all Plack-y and modern, plackup jacquard_web.psgi
, and
then browse to the URL the server reports it's running on. You should
see the Catalyst welcome page at that point. Add '/hello_user' to the
end of the URL, and you should get prompted for a username and
password. Assuming you created an account using the helper script from
the [last installment][lastinstallment], you should be able to give
those same values and see a page that says 'Hello' and your test
account username.
Now, are we done? Not quite, as we don't have any tests of the
authentication code! The following goes in
t/lib/Test/Jacquard/Web/Controller/Root.pm
:
package Test::Jacquard::Web::Controller::Root;
use parent 'Test::BASE';
use strict;
use warnings;
use Test::Most;
use Test::WWW::Mechanize::Catalyst;
sub fixtures :Tests(startup) {
my $test = shift;
# load test config
$ENV{CATALYST_CONFIG_LOCAL_SUFFIX} = 'test';
$test->{mech} = Test::WWW::Mechanize::Catalyst->new( catalyst_app => 'Jacquard::Web' );
}
sub auth_test :Tests() {
my $test = shift;
my $mech = $test->{mech};
$mech->get_ok( '/' , 'basic request works' );
is( $mech->uri->path , '/' , 'at top page' );
$mech->get_ok( '/hello_user' , 'request hello_user' );
is( $mech->uri->path , '/login' , 'redirect to login' );
$mech->submit_form_ok({
form_id => 'login_form' ,
fields => {
username => 'test_user' ,
password => 'test_password' ,
} ,
button => 'submit' ,
} , 'login' );
is( $mech->uri->path , '/hello_user' , 'redirect to /hello_user' );
$mech->text_contains( 'Hello, test_user!' , 'see expected greeting' );
$mech->get_ok( '/' , 'basic request works' );
is( $mech->uri->path , '/' , 'at home page' );
$mech->get_ok( '/hello_user' , 'request hello_user' );
is( $mech->uri->path , '/hello_user' , 'go directly to hello_user' );
$mech->text_contains( 'Hello, test_user!' , 'still see expected greeting' );
$mech->get_ok( '/logout' );
is( $mech->uri->path , '/' , 'back at home page' );
$mech->get_ok( '/hello_user' , 'request hello_user' );
is( $mech->uri->path , '/login' , 'redirect to login' );
}
read more