X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Manual.git;a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FTutorial%2FAuthentication.pod;h=499aa5346472935ed63cae375ff2be9b553b51a8;hp=3990f74f25f8d1b9669ba55af15aca41a15bdcf9;hb=94d8da411a980c822af29da44d4cbf62a72c25c1;hpb=15e1d0b201341bf72fbf027d1450bbddac49e80f diff --git a/lib/Catalyst/Manual/Tutorial/Authentication.pod b/lib/Catalyst/Manual/Tutorial/Authentication.pod index 3990f74..499aa53 100644 --- a/lib/Catalyst/Manual/Tutorial/Authentication.pod +++ b/lib/Catalyst/Manual/Tutorial/Authentication.pod @@ -56,16 +56,16 @@ L =head1 DESCRIPTION -Now that we finally have a simple yet functional application, we can -focus on providing authentication (with authorization coming next in -Part 5). +Now that we finally have a simple yet functional application, we can +focus on providing authentication (with authorization coming next in +Part 6). This part 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 -L +L. =head1 BASIC AUTHENTICATION @@ -77,7 +77,7 @@ application. First, we add both user and role information to the database (we will add the role information here although it will not be used until the -authorization section, Part 5). Create a new SQL script file by opening +authorization section, Part 6). Create a new SQL script file by opening C in your editor and insert: -- @@ -125,24 +125,29 @@ Although we could manually edit the DBIC schema information to include 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 MyAppDB DBIC::Schema MyApp::Schema::MyAppDB create=static dbi:SQLite:myapp.db - $ ls lib/MyApp/Schema/MyAppDB + $ 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 -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-editted +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 enhancements would have been preserved. - -Speaking of "hand-editted 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<# +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;>: -C: +C: # # Set relationships: @@ -153,18 +158,18 @@ C: # 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::MyAppDB::UserRoles', 'user_id'); + __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 - # 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 + # 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_role', 'role'); -C: +C: # # Set relationships: @@ -175,10 +180,10 @@ C: # 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::MyAppDB::UserRoles', 'role_id'); + __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::UserRoles', 'role_id'); -C: +C: # # Set relationships: @@ -189,32 +194,32 @@ C: # 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::MyAppDB::Users', 'user_id'); + __PACKAGE__->belongs_to(user => 'MyApp::Schema::Users', '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::MyAppDB::Roles', 'role_id'); + __PACKAGE__->belongs_to(role => 'MyApp::Schema::Roles', '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 +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 Part 3. -Note that we do not need to make any change to the -C schema file. It simple tells DBIC to -load all of the result source files it finds in below the -C directory, so it will automatically pick +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 files it finds in below the +C directory, so it will automatically pick up our new table information. =head2 Sanity-Check Reload of Development Server -We aren't ready to try out the authentication just yet; we only want -to do a quick check to be sure our model loads correctly. Press -C to kill the previous server instance (if it's still running) +We aren't ready to try out the authentication just yet; we only want +to do a quick check to be sure our model loads correctly. Press +C to kill the previous server instance (if it's still running) and restart it: $ script/myapp_server.pl @@ -227,117 +232,121 @@ Look for the three new model objects in the startup debug output: +-------------------------------------------------------------------+----------+ | MyApp::Controller::Books | instance | | MyApp::Controller::Root | instance | - | MyApp::Model::MyAppDB | instance | - | MyApp::Model::MyAppDB::Author | class | - | MyApp::Model::MyAppDB::Books | class | - | MyApp::Model::MyAppDB::BookAuthors | class | - | MyApp::Model::MyAppDB::Roles | class | - | MyApp::Model::MyAppDB::Users | class | - | MyApp::Model::MyAppDB::UserRoles | class | + | MyApp::Model::DB | instance | + | MyApp::Model::DB::Author | class | + | MyApp::Model::DB::Books | class | + | MyApp::Model::DB::BookAuthors | class | + | MyApp::Model::DB::Roles | class | + | MyApp::Model::DB::Users | class | + | MyApp::Model::DB::UserRoles | class | | MyApp::View::TT | instance | '-------------------------------------------------------------------+----------' ... -Again, notice that your "result source" classes have been "re-loaded" +Again, notice that your "result class" classes have been "re-loaded" by Catalyst under C. =head2 Include Authentication and Session Plugins -Edit C and update it as follows (everything below +Edit C and update it as follows (everything below C is new): - use Catalyst qw/ + __PACKAGE__->setup(qw/ -Debug ConfigLoader Static::Simple - + StackTrace - + Authentication - + Session Session::Store::FastMmap Session::State::Cookie - /; + /); + +B As discussed in MoreCatalystBasics, different versions of +C have used a variety of methods to load the plugins. +You put the plugins in the C statement if you prefer. -The C plugin supports Authentication while the -C plugins are required to maintain state across multiple HTTP -requests. +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 +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). -Note that there are several options for -L -(L -is generally a good choice if you are on Unix; try -L if you -are on Win32) -- consult -L and its subclasses +Note that there are several options for +L +(L +is generally a good choice if you are on Unix; try +L if you +are on Win32) -- consult +L and its subclasses for additional information and options (for example to use a database- backed session store). =head2 Configure Authentication -Although C<__PACKAGE__-Econfig(name =E 'value');> is still -supported, newer Catalyst applications tend to place all configuration -information in C and automatically load this information -into Cconfig> using the -L plugin. - -First, as noted in Part 3 of the tutorial, Catalyst has recently -switched from a default config file format of YAML to -C (an apache-like format). In case you are using -a version of Catalyst earlier than v5.7014, delete the C -file and simply follow the directions below to create a new -C file. - -Here, we need to load several parameters that tell -L -where to locate information in your database. To do this, edit the +Although C<__PACKAGE__-Econfig(name =E 'value');> is still +supported, newer Catalyst applications tend to place all configuration +information in C and automatically load this information +into Cconfig> using the +L plugin. + +First, as noted in Part 3 of the tutorial, Catalyst has recently +switched from a default config file format of YAML to +C (an apache-like format). In case you are using a +version of Catalyst earlier than v5.7014, delete the C, or +convert it to .conf format using the TIP in +L; then simply follow the +directions below to create a new C file. + +Here, we need to load several parameters that tell +L +where to locate information in your database. To do this, edit the C 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 default_realm dbic - # Note this first definition would be the same as setting + # Note: this first definition would be the same as setting # __PACKAGE__->config->{authentication}->{realms}->{dbic} - # ->{credential} = 'Password' in lib/MyApp.pm + # ->{credential} = 'Password' in lib/MyApp.pm # # Specify that we are going to do password-based auth class Password # This is the name of the field in the users table with the # password stored in it password_field password - # We are using an unencrypted password now + # We are using an unencrypted password for now password_type clear # Use DBIC to retrieve username, password & role information class DBIx::Class - # This is the model object created by Catalyst::Model::DBIC - # from your schema (you created 'MyAppDB::User' but as the - # Catalyst startup debug messages show, it was loaded as - # 'MyApp::Model::MyAppDB::Users'). - # NOTE: Omit 'MyApp::Model' here just as you would when using - # '$c->model("MyAppDB::Users)' - user_class MyAppDB::Users - # This is the name of the field in your 'users' table that - # contains the user's name - id_field username + # This is the model object created by Catalyst::Model::DBIC + # from your schema (you created 'MyApp::Schema::User' but as + # the Catalyst startup debug messages show, it was loaded as + # 'MyApp::Model::DB::Users'). + # NOTE: Omit 'MyApp::Model' here just as you would when using + # '$c->model("DB::Users)' + user_class DB::Users - - + + Inline comments in the code above explain how each field is being used. @@ -345,6 +354,7 @@ Note that you can use many other config file formats with catalyst. See L for details. + =head2 Add Login and Logout Controllers Use the Catalyst create script to create two stub controller files: @@ -352,18 +362,16 @@ Use the Catalyst create script to create two stub controller files: $ script/myapp_create.pl controller Login $ script/myapp_create.pl controller Logout -B: You could easily use a single controller here. For example, +B You could easily use a single controller here. For example, you could 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 (this 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: +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: =head2 index @@ -371,7 +379,7 @@ Then update it to match: =cut - sub index : Private { + sub index :Path :Args(0) { my ($self, $c) = @_; # Get the username and password from form @@ -381,8 +389,8 @@ Then update it to match: # 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} )) { + if ($c->authenticate({ username => $username, + password => $password } )) { # If successful, then let them use the application $c->response->redirect($c->uri_for('/books/list')); return; @@ -397,31 +405,30 @@ Then update it to match: } 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 -will stay at the login page but receive an error message. If the -C and C values are not present in the form, 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 +will stay at the login page and receive an error message. If the +C and C 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; -however, the use of C actions is discouraged because it does -not receive path args as with other actions. The recommended practice -is to only use C in C. - -Another option would be to use something like -C (where the C<...> refers to the login -code shown in C above). We are using C here to specifically match the URL C. -C actions (aka, "literal actions") create URI matches relative to -the namespace of the controller where they are defined. Although -C supports arguments that allow relative and absolute paths to be -defined, here we use an empty C definition to match on just the -name of the controller itself. The method name, C, is arbitrary. -We make the match even more specific with the C<:Args(0)> action -modifier -- this forces the match on I C, not +Note that we could have used something like C, +however, it is generally recommended (partly for historical reasons, +and partly for code clarity) only to use C in +C, and then mainly to generate the 404 not +found page for the application. + +Instead, we are using C here to +specifically match the URL C. C actions (aka, "literal +actions") create URI matches relative to the namespace of the +controller where they are defined. Although C supports +arguments that allow relative and absolute paths to be defined, here +we use an empty C definition to match on just the name of the +controller itself. The method name, C, is arbitrary. We make +the match even more specific with the C<:Args(0)> action modifier -- +this forces the match on I C, not C. -Next, update the corresponding method in +Next, update the corresponding method in C to match: =head2 index @@ -430,7 +437,7 @@ C to match: =cut - sub index : Private { + sub index :Path :Args(0) { my ($self, $c) = @_; # Clear the user's state @@ -440,8 +447,8 @@ C to match: $c->response->redirect($c->uri_for('/')); } -As with the login controller, be sure to delete the -C<$c->response->body('Matched MyApp::Controller::Logout in Logout.');> +As with the login controller, be sure to delete the +C<$c-Eresponse-Ebody('Matched MyApp::Controller::Logout in Logout.');> line of the C. @@ -452,7 +459,7 @@ Create a login form by opening C and inserting: [% META title = 'Login' %] -
+ @@ -488,16 +495,16 @@ the following method: =cut # Note that 'auto' runs after 'begin' but before your actions and that - # 'auto' "chain" (all from application path to most specific class are run) + # '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 C action we + # to only allow unauthenticated access to the 'index' action we # added above. if ($c->controller eq $c->controller('Login')) { return 1; @@ -518,34 +525,34 @@ the following method: } -B Catalyst provides a number of different types of actions, -such as C, C, C and the new C. You -should refer to L for -a more detailed explanation, but the following bullet points provide a +B Catalyst provides a number of different types of actions, +such as C, C, C and the new C. You +should refer to L for +a more detailed explanation, but the following bullet points provide a quick introduction: =over 4 =item * -The majority of application have traditionally use C actions -for items that respond to user requests and C actions for +The majority of application have traditionally used C actions +for items that respond to user requests and C actions for those that do not directly respond to user input. =item * -Newer Catalyst applications tend to use C actions and the +Newer Catalyst applications tend to use C actions and the C attribute because of their power and flexibility. You can specify the path to match relative to the namespace of the current module as an argument to C. For example C in -C would match on the URL -C but C would +C would match on the URL +C but C would match on C. =item * -Automatic "chaining" of actions by the dispatcher is a powerful -feature that allows multiple methods to handle a single URL. See +Automatic "chaining" of actions by the dispatcher is a powerful +feature that allows multiple methods to handle a single URL. See L for more information on chained actions. @@ -558,14 +565,14 @@ C, C, and C. With C, C, C, C private actions, only the most specific action of each type will be called. For example, if you -define a C action in your controller it will I a +define a C action in your controller it will I a C action in your application/root controller -- I the action in your controller will be called. =item * -Unlike the other actions where only a single method is called for each -request, I auto action along the chain of namespaces will be +Unlike the other actions where only a single method is called for each +request, I auto action along the chain of namespaces will be called. Each C action will be called I. @@ -585,20 +592,20 @@ lines to the bottom of the file:

[% - # This code illustrates how certain parts of the TT + # This code illustrates how certain parts of the TT # template will only be shown to users who have logged in %] - [% IF Catalyst.user_exists %] - Please Note: You are already logged in as '[% Catalyst.user.username %]'. - You can logout here. + [% IF c.user_exists %] + Please Note: You are already logged in as '[% c.user.username %]'. + You can logout here. [% ELSE %] You need to log in to use this application. [% END %] [%# Note that this whole block is a comment because the "#" appears - immediate after the "[%" (with no spaces in between). Although it - can be a handy way to temporarily "comment out" a whole block of - TT code, it's probably a little too subtle for use in "normal" + immediate after the "[%" (with no spaces in between). Although it + can be a handy way to temporarily "comment out" a whole block of + TT code, it's probably a little too subtle for use in "normal" comments. %]

@@ -617,38 +624,38 @@ running) and restart it: $ script/myapp_server.pl -B: If you happen to be using Internet Explorer, you may -need to use the command C
Username: