=head1 NAME Catalyst::Manual::Tutorial::05_Authentication - Catalyst Tutorial - Chapter 5: Authentication =head1 OVERVIEW This is B for the Catalyst tutorial. L =over 4 =item 1 L =item 2 L =item 3 L =item 4 L =item 5 B<05_Authentication> =item 6 L =item 7 L =item 8 L =item 9 L =item 10 L =back =head1 DESCRIPTION Now that we finally have a simple yet functional application, we can focus on providing authentication (with authorization coming next in Chapter 6). 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 L. =head1 BASIC AUTHENTICATION This section explores how to add authentication logic to a Catalyst application. =head2 Add Users and Roles to the Database 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, Chapter 6). Create a new SQL script file by opening C in your editor and insert: -- -- Add user and role tables, along with a many-to-many join table -- PRAGMA foreign_keys = ON; CREATE TABLE user ( id INTEGER PRIMARY KEY, username TEXT, password TEXT, email_address TEXT, first_name TEXT, last_name TEXT, active INTEGER ); CREATE TABLE role ( id INTEGER PRIMARY KEY, role TEXT ); CREATE TABLE user_role ( 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) ); -- -- Load up some initial test data -- INSERT INTO user VALUES (1, 'test01', 'mypass', 't01@na.com', 'Joe', 'Blow', 1); INSERT INTO user VALUES (2, 'test02', 'mypass', 't02@na.com', 'Jane', 'Doe', 1); INSERT INTO user VALUES (3, 'test03', 'mypass', 't03@na.com', 'No', 'Go', 0); INSERT INTO role VALUES (1, 'user'); INSERT INTO role VALUES (2, 'admin'); INSERT INTO user_role VALUES (1, 1); INSERT INTO user_role VALUES (1, 2); INSERT INTO user_role VALUES (2, 1); INSERT INTO user_role VALUES (3, 1); 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 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 \ 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 ... Schema dump completed. exists "/root/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 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 the C relationship information to the User Result Source file. 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 roles (see L), we will also manually add a C relationship. Edit C add the following information between the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing C<1;>: # 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 => '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 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 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 C directory, so it will automatically pick up our new table information. =head2 Sanity-Check of the Development Server Reload 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. Assuming that you are following along and using the "-r" option on C, then the development server should automatically reload (if not, press C to break out of the server if it's running and then enter C