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=358c3988a11268a9954aca52dc6588c1f6c8bcbe;hp=5effaac1438effa62aebdd7b32e6a0ec298a7983;hb=ddfbd8506f744fe1dc407bdaa7a1e9211b2dd1d7;hpb=4370705338dd0a8e1d416467beb0ddb1bc62e877 diff --git a/lib/Catalyst/Manual/Tutorial/05_Authentication.pod b/lib/Catalyst/Manual/Tutorial/05_Authentication.pod index 5effaac..358c398 100644 --- a/lib/Catalyst/Manual/Tutorial/05_Authentication.pod +++ b/lib/Catalyst/Manual/Tutorial/05_Authentication.pod @@ -81,6 +81,7 @@ add the role information here although it will not be used until the authorization section, Chapter 6). Create a new SQL script file by opening C in your editor and insert: + PRAGMA foreign_keys = ON; -- -- Add user and role tables, along with a many-to-many join table -- @@ -98,8 +99,8 @@ C in your editor and insert: role TEXT ); CREATE TABLE user_role ( - user_id INTEGER, - role_id INTEGER, + user_id INTEGER REFERENCES user(id) ON DELETE CASCADE ON UPDATE CASCADE, + role_id INTEGER REFERENCES role(id) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (user_id, role_id) ); -- @@ -119,6 +120,7 @@ Then load this into the C database with the following command: $ sqlite3 myapp.db < myapp02.sql + =head2 Add User and Role Information to DBIC Schema Although we could manually edit the DBIC schema information to include @@ -126,7 +128,8 @@ the new tables added in the previous step, let's use the C 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 components=TimeStamp dbi:SQLite:myapp.db + 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 ... @@ -150,63 +153,18 @@ DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing C<1;>: C: - # - # 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 (aka, foreign key in peer table) - __PACKAGE__->has_many(map_user_roles => 'MyApp::Schema::Result::UserRole', 'user_id'); - + # many_to_many(): # args: # 1) Name of relationship, DBIC will create accessor with this name # 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 => 'map_user_roles', 'role'); + __PACKAGE__->many_to_many(roles => 'user_roles', 'role'); -C: - - # - # 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 (aka, foreign key in peer table) - __PACKAGE__->has_many(map_user_roles => 'MyApp::Schema::Result::UserRole', 'role_id'); - - -C: - - # - # 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::Result::User', 'user_id'); - - # 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(role => 'MyApp::Schema::Result::Role', 'role_id'); - -The code for these three sets of updates is obviously very similar to -the edits we made to the C, C, and C -classes created in Chapter 3. +The code for this update is obviously very similar to the edits we made to the +C and C classes created in Chapter 3. Note that we do not need to make any change to the C schema file. It simply tells DBIC to load all @@ -268,8 +226,9 @@ C is new): /; B As discussed in MoreCatalystBasics, different versions of -C have used a variety of methods to load the plugins. -You can put the plugins in the C statement if you prefer. +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. The C plugin supports Authentication while the C plugins are required to maintain state across multiple HTTP @@ -285,17 +244,17 @@ configuration (see below). Make sure you include the additional plugins as new dependencies in the Makefile.PL file something like this: - requires ( - 'Catalyst::Plugin::Authentication' => '0', - 'Catalyst::Plugin::Session' => '0', - 'Catalyst::Plugin::Session::Store::FastMmap' => '0', - 'Catalyst::Plugin::Session::State::Cookie' => '0', - ); + requires 'Catalyst::Plugin::Authentication'; + requires 'Catalyst::Plugin::Session'; + requires 'Catalyst::Plugin::Session::Store::FastMmap'; + requires 'Catalyst::Plugin::Session::State::Cookie'; Note that there are several options for L -(L -is generally a good choice if you are on Unix; try + +(L or +L is +generally a good choice if you are on Unix; try L if you are on Win32) -- consult L and its subclasses @@ -334,7 +293,6 @@ for the tutorial, but if you wish to use C, just convert to the following code: - use_session 1 password_type clear user_model DB::User @@ -387,8 +345,8 @@ and update the definition of C to match: my ($self, $c) = @_; # Get the username and password from form - my $username = $c->request->params->{username} || ""; - my $password = $c->request->params->{password} || ""; + 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) { @@ -403,6 +361,9 @@ and update the definition of C to match: # Set an error message $c->stash->{error_msg} = "Bad username or password."; } + } else { + # Set an error message + $c->stash->{error_msg} = "Empty username or password."; } # If either of above don't work out, send to the login page @@ -489,9 +450,8 @@ Create a login form by opening C and inserting: We need something that provides enforcement for the authentication mechanism -- a I mechanism that prevents users who have not passed authentication from reaching any pages except the login page. -This is generally done via an C action/method (prior to Catalyst -v5.66, this sort of thing would go in C, but starting in -v5.66, the preferred location is C). +This is generally done via an C action/method in +C. Edit the existing C class file and insert the following method: @@ -505,7 +465,7 @@ the following method: # 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 { + sub auto :Private { my ($self, $c) = @_; # Allow unauthenticated users to reach the login page. This @@ -650,16 +610,6 @@ between the browser and your application, consider using SSL/TLS, made easy with the Catalyst plugin Catalyst::Plugin:RequireSSL. -=head2 Install DBIx::Class::EncodedColumn - -L provides features -that can greatly simplify the maintenance of passwords. It's currently -not available as a .deb package in the normal Debian repositories, so let's -install it directly from CPAN: - - $ sudo cpan DBIx::Class::EncodedColumn - - =head2 Re-Run the DBIC::Schema Model Helper to Include DBIx::Class::EncodedColumn Next, we can re-run the model helper to have it include @@ -669,14 +619,15 @@ saw in Chapters 3 and 4, but add C<,EncodedColumn> to the C argument: $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \ - create=static components=TimeStamp,EncodedColumn dbi:SQLite:myapp.db + create=static components=TimeStamp,EncodedColumn dbi:SQLite:myapp.db \ + on_connect_do="PRAGMA foreign_keys = ON" If you then open one of the Result Classes, you will see that it includes EncodedColumn in the C line. Take a look at C since that's the main class where we want to use hashed and salted passwords: - __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp", "EncodedColumn", "Core"); + __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp", "EncodedColumn"); =head2 Modify the "password" Column to Use EncodedColumn @@ -748,7 +699,7 @@ Then run the following command: $ DBIC_TRACE=1 perl -Ilib set_hashed_passwords.pl -We had to use the C<-Ilib> arguement 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: @@ -771,7 +722,9 @@ But we can further confirm our actions by dumping the users table: 3|test03|af929a151340c6aed4d54d7e2651795d1ad2e2f7UW8dHoGv9z|t03@na.com|No|Go|0 As you can see, the passwords are much harder to steal from the -database. Also note that this demonstrates how to use a DBIx::Class +database (not only are the hashes stored, but every hash is different +even though the passwords are the same because of the added "salt" +value). Also note that this demonstrates how to use a DBIx::Class model outside of your web application -- a very useful feature in many situations. @@ -892,7 +845,7 @@ C<__PACKAGE__-Econfig> setting to something like: __PACKAGE__->config( name => 'MyApp', - session => {flash_to_stash => 1} + session => { flash_to_stash => 1 }, ); B add the following to C: