X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Manual.git;a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FTutorial%2F05_Authentication.pod;h=c6f43dbe85f784fc77e5d4a43f2bfa62fe35a59a;hp=b01f4464dff0ebd483b527f9d655ccf099be4e2c;hb=477a6d5b13f55eb335979812080e4a11217f19d6;hpb=8fefbef869d13800721f91ef15229da60889d12d diff --git a/lib/Catalyst/Manual/Tutorial/05_Authentication.pod b/lib/Catalyst/Manual/Tutorial/05_Authentication.pod index b01f446..c6f43db 100644 --- a/lib/Catalyst/Manual/Tutorial/05_Authentication.pod +++ b/lib/Catalyst/Manual/Tutorial/05_Authentication.pod @@ -63,8 +63,9 @@ L). This chapter of the tutorial is divided into two main sections: 1) basic, 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 +Source code for the tutorial in included in the F directory +of the Tutorial Virtual machine (one subdirectory per chapter). There +are also instructions for downloading the code in L. @@ -131,11 +132,11 @@ for us: $ 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 @@ -143,14 +144,14 @@ for us: Notice how the helper has added three new table-specific Result Source files to the C 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-edited +files, those changes would have only been written above the +C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and your hand-edited enhancements would have been preserved. Speaking of "hand-edited enhancements," we should now add the C relationship information to the User Result Source file. -As with the Book, BookAuthor, and Author files in L, +As with the Book, BookAuthor, and Author files in +L, L has automatically created the C and C relationships for the new User, UserRole, and Role tables. However, as a convenience for mapping Users to their assigned @@ -166,10 +167,11 @@ C<1;>: # 2) Name of has_many() relationship this many_to_many() is shortcut for # 3) Name of belongs_to() relationship in model class of has_many() above # You must already have the has_many() defined to use a many_to_many(). - __PACKAGE__->many_to_many(roles => 'user_roles', 'role_id'); + __PACKAGE__->many_to_many(roles => 'user_roles', 'role'); The code for this update is obviously very similar to the edits we made -to the C and C classes created in Chapter 3 with one +to the C and C classes created in +L with one exception: we only defined the C relationship in one direction. Whereas we felt that we would want to map Authors to Books B Books to Authors, here we are only adding the convenience @@ -177,7 +179,7 @@ C in the Users to Roles direction. Note that we do not need to make any change to the C schema file. It simply tells DBIC to load all of -the Result Class and ResultSet Class files it finds in below the +the Result Class and ResultSet Class files it finds below the C directory, so it will automatically pick up our new table information. @@ -233,21 +235,24 @@ C is new): Session::State::Cookie /; -B As discussed in MoreCatalystBasics, different versions of -C have used a variety of methods to load the plugins, -but we are going to use the current Catalyst 5.8X practice of putting -them on the C line. +B As discussed in +L, +different versions of C have used a variety of methods +to load the plugins, but we are going to use the current Catalyst 5.9 +practice of putting them on the C line. The C plugin supports Authentication while the C plugins are required to maintain state across multiple HTTP requests. Note that the only required Authentication class is the main one. This -is a change that occurred in version 0.09999_01 of the C -plugin. You B to specify a particular Authentication::Store -or Authentication::Credential plugin. Instead, indicate the Store and -Credential you want to use in your application configuration (see -below). +is a change that occurred in version 0.09999_01 of the +L plugin. You +B to specify a particular +L or +C you want to use. Instead, indicate the +Store and Credential you want to use in your application configuration +(see below). Make sure you include the additional plugins as new dependencies in the Makefile.PL file something like this: @@ -264,7 +269,7 @@ is generally a good choice if you are on Unix. If you are running on Windows L is fine. Consult L and its subclasses for additional information and options (for example to -use a database- backed session store). +use a database-backed session store). =head2 Configure Authentication @@ -272,8 +277,11 @@ use a database- backed session store). There are a variety of ways to provide configuration information to L. Here we will use L because it automatically -sets a reasonable set of defaults for us. Open C and place -the following text above the call to C<__PACKAGE__-Esetup();>: +sets a reasonable set of defaults for us. (Note: the C here +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 and place the +following text above the call to C<__PACKAGE__-Esetup();>: # Configure SimpleDB Authentication __PACKAGE__->config( @@ -315,13 +323,13 @@ B, if you try out the command above, be sure to delete the "myapp.conf" command. Otherwise, you will wind up with duplicate configurations. -B Because we are using 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 being said, -SimpleDB lets you specify that type of information if you need to. Take -a look at -C +B Because we are using +L 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 +being said, SimpleDB lets you specify that type of information if you +need to. Take a look at C for details. @@ -337,11 +345,8 @@ have a C controller with both C and C actions. Remember, Catalyst is designed to be very flexible, and leaves such matters up to you, the designer and programmer. -Then open C, locate the -C method (or C if you are -using an older version of Catalyst) that was automatically inserted by -the helpers when we created the Login controller above, and update the -definition of C to match: +Then open C, and update the definition of +C to match: =head2 index @@ -379,10 +384,6 @@ definition of C to match: $c->stash(template => 'login.tt2'); } -Be sure to remove the -C<$c-Eresponse-Ebody('Matched MyApp::Controller::Login in Login.');> -line of the C. - This controller fetches the C and C values from the login form and attempts to authenticate the user. If successful, it redirects the user to the book list page. If the login fails, the user @@ -425,10 +426,6 @@ C to match: $c->response->redirect($c->uri_for('/')); } -As with the login controller, be sure to delete the -C<$c-Eresponse-Ebody('Matched MyApp::Controller::Logout in Logout.');> -line of the C. - =head2 Add a Login Form TT Template Page @@ -558,18 +555,15 @@ C and password C, and you should be taken to the Book List page. B 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. You can quickly sync a Debian system by -installing the "ntpdate" package: - - sudo aptitude -y install ntpdate - -And then run the following command: +Internet Explorer (or potentially other browsers), be sure to check the +system clocks on both your server and client machines. Internet +Explorer is very picky about timestamps for cookies. You can use the +C command on the Tutorial Virtual Machine to check time sync +and/or use the following command to force a sync: sudo ntpdate-debian -Or, depending on your firewall configuration: +Or, depending on your firewall configuration, try it with "-u": sudo ntpdate-debian -u @@ -602,8 +596,8 @@ need to log in to use this application." In this section we increase the security of our system by converting from cleartext passwords to SHA-1 password hashes that include a random -"salt" value to make them extremely difficult to crack with dictionary -and "rainbow table" attacks. +"salt" value to make them extremely difficult to crack, even with +dictionary and "rainbow table" attacks. B This section is optional. You can skip it and the rest of the tutorial will function normally. @@ -613,13 +607,13 @@ browser still transmits the passwords in cleartext to your application. We are just avoiding the I of cleartext passwords in the database by using a salted SHA-1 hash. If you are concerned about cleartext passwords between the browser and your application, consider -using SSL/TLS, made easy with the Catalyst plugin -L. +using SSL/TLS, made easy with modules such as +L and L. =head2 Re-Run the DBIC::Schema Model Helper to Include DBIx::Class::PassphraseColumn -Next, we can re-run the model helper to have it include +Let's re-run the model helper to have it include L in all of the Result Classes it generates for us. Simply use the same command we saw in Chapters 3 and 4, but add C<,PassphraseColumn> to the C argument: @@ -701,7 +695,7 @@ Then run the following command: $ DBIC_TRACE=1 perl -Ilib set_hashed_passwords.pl -We had to use the C<-Ilib> argument to tell perl to look under the +We had to use the C<-Ilib> argument to tell Perl to look under the C directory for our C model. The DBIC_TRACE output should show that the update worked: @@ -732,7 +726,8 @@ your web application -- a very useful feature in many situations. =head2 Enable Hashed and Salted Passwords -Edit C and update it to match the following text (the only +Edit C and update the config() section for +C it to match the following text (the only change is to the C field): # Configure SimpleDB Authentication @@ -830,44 +825,137 @@ next screen where it's appropriate, but it won't "keep showing up" after that first time (unless you reset it). Please refer to L for additional information. +B There is also a C feature that will +automatically load the contents the contents of flash into stash, +allowing us to use the more typical C in our TT +template in lieu of the more verbose C +we used above. Consult L for additional +information. + + +=head2 Switch To Catalyst::Plugin::StatusMessages + +Although the query parameter technique we used in +L and the C +approach we used above will work in most cases, they both have their +drawbacks. The query parameters can leave the status message on the +screen longer than it should (for example, if the user hits refresh). +And C can display the wrong message on the wrong screen (flash +just shows the message on the next page for that user... if the user +has multiple windows or tabs open, then the wrong one can get the +status message). + +L is designed to address these +shortcomings. It stores the messages in the user's session (so they are +available across multiple requests), but ties each status message to a +random token. By passing this token across the redirect, we are no +longer relying on a potentially ambiguous "next request" like we do with +flash. And, because the message is deleted the first time it's +displayed, the user can hit refresh and still only see the message a +single time (even though the URL may continue to reference the token, +it's only displayed the first time). The use of C +or a similar mechanism is recommended for all Catalyst applications. + +To enable C, first edit C and add +C to the list of plugins: -=head2 Switch To Flash-To-Stash + use Catalyst qw/ + -Debug + ConfigLoader + Static::Simple + + StackTrace + + Authentication + + Session + Session::Store::File + Session::State::Cookie + + StatusMessage + /; -Although the use of flash above works well, the -C statement is a little ugly. A nice -alternative is to use the C feature that automatically -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, you can either set -the value in C by changing the default -C<__PACKAGE__-Econfig> setting to something like: +Then edit C and modify the C +action to match the following: - __PACKAGE__->config( - name => 'MyApp', - # Disable deprecated behavior needed by old applications - disable_component_resolution_regex_fallback => 1, - 'Plugin::Session' => { flash_to_stash => 1 }, - ); + 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")})); + } + +This uses the C that the plugin added to C<$c> to save +the message under a random token. (If we wanted to save an error +message, we could have used C.) Because +C and C both return the random token, we +can assign that value to the "C" query parameter via C as +shown above. + +Next, we need to make sure that the list page will load display the +message. The easiest way to do this is to take advantage of the chained +dispatch we implemented in +L. Edit +C again and update the C action to +match: + + 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; + } -B add the following to C: +That way, anything that chains off C will automatically get any +status or error messages loaded into the stash. Let's convert the +C action to take advantage of this. Modify the method signature +for C from: - - flash_to_stash 1 - + sub list :Local { -The C<__PACKAGE__-Econfig> 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. +to: -Then edit C and change the C line to -match the following: + sub list :Chained('base') :PathParth('list') :Args(0) { - [% status_msg %] +Finally, let's clean up the status/error message code in our wrapper +template. Edit C and change the "content" div +to match the following: + +
+ [%# Status and error messages %] + [% status_msg %] + [% error_msg %] + [%# This is where TT will stick all of your template's contents. -%] + [% content %] +
Now go to L in your browser. Delete -another of the "Test" books you added in the previous step. Flash should -still maintain the status message across the redirect even though you -are no longer explicitly accessing C. +another of the "Test" books you added in the previous step. You should +get redirection from the C action back to the C action, +but with a "mid=########" message ID query parameter. The screen should +say "Deleted book #" (where # is the PK id of the book you removed). +However, if you hit refresh in your browser, the status message is no +longer displayed (even though the URL does still contain the message ID +token, it is ignored -- thereby keeping the state of our status/error +messages in sync with the users actions). + + +You can jump to the next chapter of the tutorial here: +L =head1 AUTHOR @@ -876,11 +964,8 @@ Kennedy Clark, C 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 -. - -The most recent version of the Catalyst Tutorial can be found at -L. +L. -Copyright 2006-2010, Kennedy Clark, under the +Copyright 2006-2011, Kennedy Clark, under the Creative Commons Attribution Share-Alike License Version 3.0 (L).