This chapter of the tutorial is divided into two main sections: 1)
basic, cleartext authentication and 2) hash-based authentication.
-Source code for the tutorial in included in the F</root/Final> directory
+Source code for the tutorial in included in the F</home/catalyst/Final> directory
of the Tutorial Virtual machine (one subdirectory per chapter). There
are also instructions for downloading the code in
L<Catalyst::Manual::Tutorial::01_Intro>.
$ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
create=static components=TimeStamp dbi:SQLite:myapp.db \
on_connect_do="PRAGMA foreign_keys = ON"
- exists "/root/dev/MyApp/script/../lib/MyApp/Model"
- exists "/root/dev/MyApp/script/../t"
- Dumping manual schema for MyApp::Schema to directory /root/dev/MyApp/script/../lib ...
+ exists "/home/catalyst/dev/MyApp/script/../lib/MyApp/Model"
+ exists "/home/catalyst/dev/MyApp/script/../t"
+ Dumping manual schema for MyApp::Schema to directory /home/catalyst/dev/MyApp/script/../lib ...
Schema dump completed.
- exists "/root/dev/MyApp/script/../lib/MyApp/Model/DB.pm"
+ exists "/home/catalyst/dev/MyApp/script/../lib/MyApp/Model/DB.pm"
$
$ ls lib/MyApp/Schema/Result
Author.pm BookAuthor.pm Book.pm Role.pm User.pm UserRole.pm
-Debug
ConfigLoader
Static::Simple
-
+
StackTrace
-
+
Authentication
-
+
Session
Session::Store::File
Session::State::Cookie
has nothing to do with the SimpleDB offered in Amazon's web services
offerings -- here we are only talking about a "simple" way to use your
DB as an authentication backend.) Open C<lib/MyApp.pm> and place the
-following text above the call to C<__PACKAGE__-E<gt>setup();>:
+following text above the call to C<< __PACKAGE__->setup(); >>:
# Configure SimpleDB Authentication
__PACKAGE__->config(
configurations.
B<NOTE:> Because we are using
-L<SimpleDB|L<Catalyst::Authentication::Realm::SimpleDB> along with a
+L<SimpleDB|Catalyst::Authentication::Realm::SimpleDB> along with a
database layout that complies with its default assumptions: we don't
need to specify the names of the columns where our username and password
information is stored (hence, the "Simple" part of "SimpleDB"). That
C<sub index> to match:
=head2 index
-
+
Login logic
-
+
=cut
-
+
sub index :Path :Args(0) {
my ($self, $c) = @_;
-
+
# Get the username and password from form
my $username = $c->request->params->{username};
my $password = $c->request->params->{password};
-
+
# If the username and password values were found in form
if ($username && $password) {
# Attempt to log the user in
$c->stash(error_msg => "Empty username or password.")
unless ($c->user_exists);
}
-
+
# If either of above don't work out, send to the login page
$c->stash(template => 'login.tt2');
}
C<lib/MyApp/Controller/Logout.pm> to match:
=head2 index
-
+
Logout logic
-
+
=cut
-
+
sub index :Path :Args(0) {
my ($self, $c) = @_;
-
+
# Clear the user's state
$c->logout;
-
+
# Send the user to the starting point
$c->response->redirect($c->uri_for('/'));
}
Create a login form by opening C<root/src/login.tt2> and inserting:
[% META title = 'Login' %]
-
+
<!-- Login form -->
<form method="post" action="[% c.uri_for('/login') %]">
<table>
the following method:
=head2 auto
-
+
Check if there is a user and, if not, forward to login page
-
+
=cut
-
+
# Note that 'auto' runs after 'begin' but before your actions and that
# 'auto's "chain" (all from application path to most specific class are run)
# See the 'Actions' section of 'Catalyst::Manual::Intro' for more info.
sub auto :Private {
my ($self, $c) = @_;
-
+
# Allow unauthenticated users to reach the login page. This
# allows unauthenticated users to reach any action in the Login
# controller. To lock it down to a single action, we could use:
if ($c->controller eq $c->controller('Login')) {
return 1;
}
-
+
# If a user doesn't exist, force login
if (!$c->user_exists) {
# Dump a log message to the development server debug output
# Return 0 to cancel 'post-auto' processing and prevent use of application
return 0;
}
-
+
# User found, so return 1 to continue with processing after this 'auto'
return 1;
}
passphrase_class => 'SaltedDigest',
passphrase_args => {
algorithm => 'SHA-1',
- salt_random => 20.
+ salt_random => 20,
},
passphrase_check_method => 'check_password',
},
text:
#!/usr/bin/perl
-
+
use strict;
use warnings;
-
+
use MyApp::Schema;
-
+
my $schema = MyApp::Schema->connect('dbi:SQLite:myapp.db');
-
+
my @users = $schema->resultset('User')->all;
-
+
foreach my $user (@users) {
$user->password('mypass');
$user->update;
);
The use of C<self_check> will cause
-Catalyst::Plugin::Authentication::Store::DBIC to call the
+Catalyst::Plugin::Authentication::Store::DBIx::Class to call the
C<check_password> method we enabled on our C<password> columns.
changed):
=head2 delete
-
+
Delete a book
-
+
=cut
-
+
sub delete :Chained('object') :PathPart('delete') :Args(0) {
my ($self, $c) = @_;
-
+
# Use the book object saved by 'object' and delete it along
# with related 'book_authors' entries
$c->stash->{object}->delete;
-
+
# Use 'flash' to save information across requests until it's read
$c->flash->{status_msg} = "Book deleted";
-
+
# Redirect the user back to the list page
$c->response->redirect($c->uri_for($self->action_for('list')));
}
Although the sample above only shows the C<content> div, leave the rest
of the file intact -- the only change we made to replace "||
c.request.params.status_msg" with "c.flash.status_msg" in the
-C<E<lt>span class="message"E<gt>> line.
+C<< <span class="message"> >> line.
=head2 Try Out Flash
information.
-=head2 Switch To Catalyst::Plugin::StatusMessages
+=head2 Switch To Catalyst::Plugin::StatusMessages
Although the query parameter technique we used in
L<Chapter 4|Catalyst::Manual::Tutorial::04_BasicCRUD> and the C<flash>
-Debug
ConfigLoader
Static::Simple
-
+
StackTrace
-
+
Authentication
-
+
Session
Session::Store::File
Session::State::Cookie
-
+
StatusMessage
/;
sub delete :Chained('object') :PathPart('delete') :Args(0) {
my ($self, $c) = @_;
-
+
# Saved the PK id for status_msg below
my $id = $c->stash->{object}->id;
-
+
# Use the book object saved by 'object' and delete it along
# with related 'book_authors' entries
$c->stash->{object}->delete;
-
+
# Redirect the user back to the list page
$c->response->redirect($c->uri_for($self->action_for('list'),
{mid => $c->set_status_msg("Deleted book $id")}));
sub base :Chained('/') :PathPart('books') :CaptureArgs(0) {
my ($self, $c) = @_;
-
+
# Store the ResultSet in stash so it's available for other methods
$c->stash(resultset => $c->model('DB::Book'));
-
+
# Print a message to the debug log
$c->log->debug('*** INSIDE BASE METHOD ***');
-
+
# Load status messages
$c->load_status_msgs;
}
to:
- sub list :Chained('base') :PathParth('list') :Args(0) {
+ sub list :Chained('base') :PathPart('list') :Args(0) {
Finally, let's clean up the status/error message code in our wrapper
template. Edit C<root/src/wrapper.tt2> and change the "content" div
Feel free to contact the author for any errors or suggestions, but the
best way to report issues is via the CPAN RT Bug system at
-<https://rt.cpan.org/Public/Dist/Display.html?Name=Catalyst-Manual>.
-
-The most recent version of the Catalyst Tutorial can be found at
-L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/>.
+L<https://rt.cpan.org/Public/Dist/Display.html?Name=Catalyst-Manual>.
-Copyright 2006-2010, Kennedy Clark, under the
+Copyright 2006-2011, Kennedy Clark, under the
Creative Commons Attribution Share-Alike License Version 3.0
(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).