Misc updates with thanks to JC Wren
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / Authentication.pod
index 2e7016f..499aa53 100644 (file)
@@ -65,7 +65,7 @@ cleartext authentication and 2) hash-based authentication.
 
 You can checkout the source code for this example from the catalyst
 subversion repository as per the instructions in
-L<Catalyst::Manual::Tutorial::Intro>
+L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::Intro>.
 
 =head1 BASIC AUTHENTICATION
 
@@ -126,6 +126,12 @@ the new tables added in the previous step, let's use the C<create=static>
 option on the DBIC model helper to do most of the work for us:
 
     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema create=static dbi:SQLite:myapp.db
+     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 ...
+    Schema dump completed.
+     exists "/root/dev/MyApp/script/../lib/MyApp/Model/DB.pm"
+    $
     $ ls lib/MyApp/Schema
     Authors.pm  BookAuthors.pm  Books.pm  Roles.pm  UserRoles.pm  Users.pm
 
@@ -133,11 +139,10 @@ Notice how the helper has added three new table-specific result source
 files to the C<lib/MyApp/Schema/MyApp> directory.  And, more
 importantly, even if there were changes to the existing result source
 files, those changes would have only been written above the C<# DO NOT
-MODIFY THIS OR ANYTHING ABOVE!> comment and your hand-editted
+MODIFY THIS OR ANYTHING ABOVE!> comment and your hand-edited
 enhancements would have been preserved.
 
-
-Speaking of "hand-editted enhancements," we should now add
+Speaking of "hand-edit ted enhancements," we should now add
 relationship information to the three new result source files.  Edit
 each of these files and add the following information between the C<#
 DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing C<1;>:
@@ -147,14 +152,14 @@ C<lib/MyApp/Schema/Users.pm>:
     #
     # Set relationships:
     #
-
+    
     # has_many():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
     #     2) Name of the model class referenced by this relationship
     #     3) Column name in *foreign* table
     __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::UserRoles', 'user_id');
-
+    
     # many_to_many():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
@@ -169,7 +174,7 @@ C<lib/MyApp/Schema/Roles.pm>:
     #
     # Set relationships:
     #
-
+    
     # has_many():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
@@ -183,14 +188,14 @@ C<lib/MyApp/Schema/UserRoles.pm>:
     #
     # Set relationships:
     #
-
+    
     # belongs_to():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
     #     2) Name of the model class referenced by this relationship
     #     3) Column name in *this* table
     __PACKAGE__->belongs_to(user => 'MyApp::Schema::Users', 'user_id');
-
+    
     # belongs_to():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
@@ -247,19 +252,23 @@ by Catalyst under C<MyApp::Model>.
 Edit C<lib/MyApp.pm> and update it as follows (everything below
 C<StackTrace> is new):
 
-    use Catalyst qw/
+    __PACKAGE__->setup(qw/
             -Debug
             ConfigLoader
             Static::Simple
-
+    
             StackTrace
-
+    
             Authentication
-
+    
             Session
             Session::Store::FastMmap
             Session::State::Cookie
-            /;
+        /);
+
+B<Note:> As discussed in MoreCatalystBasics, different versions of 
+C<Catalyst::Devel> have used a variety of methods to load the plugins. 
+You put the plugins in the C<use Catalyst> statement if you prefer.
 
 The C<Authentication> plugin supports Authentication while the
 C<Session> plugins are required to maintain state across multiple HTTP
@@ -304,6 +313,8 @@ L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
 where to locate information in your database.  To do this, edit the
 C<myapp.conf> file and update it to match:
 
+    # rename this file to MyApp.yml and put a : in front of "name" if
+    # you want to use yaml like in old versions of Catalyst
     name MyApp
     <authentication>
         default_realm dbic
@@ -332,9 +343,6 @@ C<myapp.conf> file and update it to match:
                     # NOTE: Omit 'MyApp::Model' here just as you would when using
                     # '$c->model("DB::Users)'
                     user_class DB::Users
-                    # This is the name of the field in your 'users' table that
-                    # contains the user's name
-                    id_field username
                 </store>
             </dbic>
         </realms>
@@ -346,6 +354,7 @@ Note that you can use many other config file formats with catalyst.
 See L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader>
 for details.
 
+
 =head2 Add Login and Logout Controllers
 
 Use the Catalyst create script to create two stub controller files:
@@ -361,31 +370,27 @@ such matters up to you, the designer and programmer.
 Then open C<lib/MyApp/Controller/Login.pm>, locate the C<sub index
 :Path :Args(0)> method (or C<sub index : Private> if you are using an
 older version of Catalyst) that was automatically inserted by the
-helpers when we created the Login controller above, and delete this
-line:
-
-    $c->response->body('Matched MyApp::Controller::Login in Login.');
-
-Then update it to match:
+helpers when we created the Login controller above, and update the
+definition of 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
             if ($c->authenticate({ username => $username,
-                                   password => $password} )) {
+                                   password => $password  } )) {
                 # If successful, then let them use the application
                 $c->response->redirect($c->uri_for('/books/list'));
                 return;
@@ -394,7 +399,7 @@ Then update it to match:
                 $c->stash->{error_msg} = "Bad username or password.";
             }
         }
-
+    
         # If either of above don't work out, send to the login page
         $c->stash->{template} = 'login.tt2';
     }
@@ -406,10 +411,10 @@ will stay at the login page and receive an error message.  If the
 C<username> and C<password> values are not present in the form, the
 user will be taken to the empty login form.
 
-Note that we could have used something like C<sub default :Path>,
-however partly for historical reasons, and partly for code clarity it
-is generally recommended only to use C<default> in
-C<MyApp::Controller::Root>, and then mainly to generate the 404 not
+Note that we could have used something like C<sub default :Path>, 
+however, it is generally recommended (partly for historical reasons, 
+and partly for code clarity) only to use C<default> in 
+C<MyApp::Controller::Root>, and then mainly to generate the 404 not 
 found page for the application.
 
 Instead, we are using C<sub base :Path :Args(0) {...}> here to
@@ -427,17 +432,17 @@ Next, update the corresponding method in
 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('/'));
     }
@@ -452,7 +457,7 @@ line of the C<sub index>.
 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>
@@ -484,19 +489,19 @@ Edit the existing C<lib/MyApp/Controller/Root.pm> class file and insert
 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 anauthenticated users to reach any action in the Login
+        # allows unauthenticated users to reach any action in the Login
         # controller.  To lock it down to a single action, we could use:
         #   if ($c->action eq $c->controller('Login')->action_for('index'))
         # to only allow unauthenticated access to the 'index' action we
@@ -504,7 +509,7 @@ the following method:
         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
@@ -514,7 +519,7 @@ the following method:
             # 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;
     }
@@ -619,21 +624,25 @@ running) and restart it:
 
     $ script/myapp_server.pl
 
-B<IMPORTANT NOTE:> If you are having issues with authentication on
-Internet Explorer, be sure to check the system clocks on both your
-server and client machines.  Internet Explorer is very picky about
-timestamps for cookies.  Note that you can quickly sync an Ubuntu
+B<IMPORTANT NOTE:> If you are having issues with authentication on 
+Internet Explorer, be sure to check the system clocks on both your 
+server and client machines.  Internet Explorer is very picky about 
+timestamps for cookies.  Note that you can quickly sync an Ubuntu 
 system with the following command:
 
     sudo ntpdate ntp.ubuntu.com
 
-Now trying going to L<http://localhost:3000/books/list> and you should
-be redirected to the login page, hitting Shift+Reload if necessary (the
-"You are already logged in" message should I<not> appear -- if it does,
-click the C<logout> button and try again). Note the C<***Root::auto User
-not found...> debug message in the development server output.  Enter
-username C<test01> and password C<mypass>, and you should be taken to
-the Book List page.
+Or possibly try C<sudo ntpdate -u ntp.ubuntu.com> (to us an 
+unpriviledged port) or C<sudo ntpdate pool.ntp.org> (to try a 
+different server in case the Ubuntu NTP server is down).
+
+Now trying going to L<http://localhost:3000/books/list> and you should 
+be redirected to the login page, hitting Shift+Reload or Ctrl+Reload 
+if necessary (the "You are already logged in" message should I<not> 
+appear -- if it does, click the C<logout> button and try again). Note 
+the C<***Root::auto User not found...> debug message in the 
+development server output.  Enter username C<test01> and password 
+C<mypass>, and you should be taken to the Book List page.
 
 Open C<root/src/books/list.tt2> and add the following lines to the
 bottom (below the closing </table> tag):
@@ -712,7 +721,7 @@ Then use the following command to update the SQLite database:
 
     $ sqlite3 myapp.db < myapp03.sql
 
-B<Note:> We are using SHA-1 hashes here, but many other hashing
+B<Note:> We are using SHA-1 hashes here, but many other hashing 
 algorithms are supported.  See C<Digest> for more information.
 
 
@@ -722,6 +731,8 @@ C<Catalyst::Plugin::Authentication::Store::DBIC>
 Edit C<myapp.conf> and update it to match (the C<password_type> and
 C<password_hash_type> are new, everything else is the same):
 
+    # rename this file to MyApp.yml and put a : in front of "name" if
+    # you want to use yaml like in old versions of Catalyst
     name MyApp
     <authentication>
         default_realm dbic
@@ -752,14 +763,12 @@ C<password_hash_type> are new, everything else is the same):
                     # NOTE: Omit 'MyApp::Model' here just as you would when using
                     # '$c->model("DB::Users)'
                     user_class DB::Users
-                    # This is the name of the field in your 'users' table that
-                    # contains the user's name
-                    id_field username
                 </store>
             </dbic>
         </realms>
     </authentication>
 
+
 =head2 Try Out the Hashed Passwords
 
 Press C<Ctrl-C> to kill the previous server instance (if it's still
@@ -789,37 +798,42 @@ to match the following (everything after the model search line of code
 has changed):
 
     =head2 delete
-
+    
     Delete a book
-
+    
     =cut
-
+    
     sub delete : Local {
         # $id = primary key of book to delete
         my ($self, $c, $id) = @_;
-
+    
         # Search for the book and then delete it
         $c->model('DB::Books')->search({id => $id})->delete_all;
-
+    
         # 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('/books/list'));
     }
 
-Next, open C<root/lib/site/layout> and update the TT code to pull from
+Next, open C<root/src/wrapper.tt2> and update the TT code to pull from
 flash vs. the C<status_msg> query parameter:
 
-    <div id="header">[% PROCESS site/header %]</div>
-
+    ...
     <div id="content">
-    <span class="message">[% status_msg || c.flash.status_msg %]</span>
-    <span class="error">[% error_msg %]</span>
-    [% content %]
-    </div>
+        [%# Status and error messages %]
+        <span class="message">[% status_msg || c.flash.status_msg %]</span>
+        <span class="error">[% error_msg %]</span>
+        [%# This is where TT will stick all of your template's contents. -%]
+        [% content %]
+    </div><!-- end content -->
+    ...
 
-    <div id="footer">[% PROCESS site/footer %]</div>
+Although the sample above only shows the C<content> div, leave the 
+rest of the file intact -- the only change we made to the C<wrapper.tt2>
+was to add "C<|| c.request.params.status_msg>" to the 
+C<E<lt>span class="message"E<gt>> line.
 
 
 =head2 Try Out Flash
@@ -838,13 +852,14 @@ after that first time (unless you reset it).  Please refer to
 L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> for additional
 information.
 
+
 =head2 Switch To Flash-To-Stash
 
 Although the a use of flash above is certainly an improvement over the
-C<status_msg> we employed in Part 4 of the tutorial, the C<status_msg
-|| c.flash.status_msg> statement is a little ugly. A nice
+C<status_msg> we employed in Part 4 of the tutorial, the 
+C<status_msg || c.flash.status_msg> statement is a little ugly. A nice
 alternative is to use the C<flash_to_stash> feature that automatically
-copies the content of flash to stash.  This makes your code controller
+copies the content of flash to stash.  This makes your controller
 and template code work regardless of where it was directly access, a
 forward, or a redirect. To enable C<flash_to_stash>, you can either
 set the value in C<lib/MyApp.pm> by changing the default
@@ -865,8 +880,8 @@ The C<__PACKAGE__-E<gt>config> option is probably preferable here
 since it's not something you will want to change at runtime without it
 possibly breaking some of your code.
 
-Then edit C<root/lib/site/layout> and change the C<status_msg> line
-to look like the following:
+Then edit C<root/src/wrapper.tt2> and change the C<status_msg> line
+to match the following:
 
     <span class="message">[% status_msg %]</span>
 
@@ -883,7 +898,7 @@ Kennedy Clark, C<hkclark@gmail.com>
 
 Please report any errors, issues or suggestions to the author.  The
 most recent version of the Catalyst Tutorial can be found at
-L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/>.
+L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
 
 Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).