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 AUTHORIZATION
In this section you learn how to manually configure authorization.
+
=head2 Update Plugins to Include Support for Authorization
Edit C<lib/MyApp.pm> and add C<Authorization::Roles> to the list:
- use Catalyst qw/
+ __PACKAGE__->setup(qw/
-Debug
ConfigLoader
Static::Simple
-
+
StackTrace
-
+
Authentication
Authorization::Roles
-
+
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 can put the plugins in the C<use Catalyst> statement if you prefer.
=head2 Add Config Information for Authorization
Edit C<myapp.conf> and update it to match the following (the
C<role_relation> and C<role_field> definitions are new):
+ # 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
# 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
# This is the name of a many_to_many relation in the users
# object that points to the roles for that user
role_relation roles
lines to the bottom of the file:
<p>Hello [% c.user.username %], you have the following roles:</p>
-
+
<ul>
[% # Dump list of roles -%]
[% FOR role = c.user.roles %]<li>[% role %]</li>[% END %]
</ul>
-
+
<p>
[% # Add some simple role-specific logic to template %]
[% # Use $c->check_user_roles() to check authz -%]
[% IF c.check_user_roles('user') %]
[% # Give normal users a link for 'logout' %]
- <a href="[% c.uri_for('/logout') %]">Logout</a>
+ <a href="[% c.uri_for('/logout') %]">User Logout</a>
[% END %]
-
+
[% # Can also use $c->user->check_roles() to check authz -%]
[% IF c.check_user_roles('admin') %]
[% # Give admin users a link for 'create' %]
- <a href="[% c.uri_for('form_create') %]">Create</a>
+ <a href="[% c.uri_for(c.controller('books').action_for('form_create')) %]">Admin Create</a>
[% END %]
</p>
This code displays a different combination of links depending on the
roles assigned to the user.
+
=head2 Limit C<Books::add> to C<admin> Users
C<IF> statements in TT templates simply control the output that is sent
updating C<url_create> to match the following code:
=head2 url_create
-
+
Create a book with the supplied title and rating,
with manual authorization
-
+
=cut
-
- sub url_create : Local {
+
+ sub url_create :Chained('base') :PathPart('url_create') :Args(3) {
# In addition to self & context, get the title, rating & author_id args
# from the URL. Note that Catalyst automatically puts extra information
# after the "/<controller_name>/<action_name/" into @_
my ($self, $c, $title, $rating, $author_id) = @_;
-
+
# Check the user's roles
if ($c->check_user_roles('admin')) {
# Call create() on the book model object. Pass the table
title => $title,
rating => $rating
});
-
+
# Add a record to the join table for this book, mapping to
# appropriate author
$book->add_to_book_authors({author_id => $author_id});
# Note: Above is a shortcut for this:
# $book->create_related('book_authors', {author_id => $author_id});
-
+
# Assign the Book object to the stash for display in the view
$c->stash->{book} = $book;
-
+
# This is a hack to disable XSUB processing in Data::Dumper
# (it's used in the view). This is a work-around for a bug in
# the interaction of some versions or Perl, Data::Dumper & DBIC.
# you are running DBIC 0.06001 or greater), but adding it doesn't
# hurt anything either.
$Data::Dumper::Useperl = 1;
-
+
# Set the TT template to use
$c->stash->{template} = 'books/create_done.tt2';
} else {
- # Provide very simple feedback to the user
+ # Provide very simple feedback to the user.
$c->response->body('Unauthorized!');
}
}
body has already been set. In reality you would probably want to use a
technique that maintains the visual continuity of your template layout
(for example, using the "status" or "error" message feature added in
-Part 3).
+Part 3 or C<detach> to an action that shows an "unauthorized" page).
B<TIP>: If you want to keep your existing C<url_create> method, you can
create a new copy and comment out the original by making it look like a
-Pod comment. For example, put something like C<=begin> before C<sub add
-: Local {> and C<=end> after the closing C<}>.
+Pod comment. For example, put something like C<=begin> before
+C<sub add : Local {> and C<=end> after the closing C<}>.
+
=head2 Try Out Authentication And Authorization
$ script/myapp_server.pl
-Now trying going to L<http://localhost:3000/books/list> and you should
-be taken to the login page (you might have to C<Shift+Reload> your
-browser and/or click the "Logout" link on the book list page). Try
-logging in with both C<test01> and C<test02> (both use a password
-of C<mypass>) and notice how the roles information updates at the
-bottom of the "Book List" page. Also try the C<Logout> link on the
-book list page.
+Now trying going to L<http://localhost:3000/books/list> and you should
+be taken to the login page (you might have to C<Shift+Reload> or
+C<Ctrl+Reload> your browser and/or click the "Logout" link on the book
+list page). Try logging in with both C<test01> and C<test02> (both
+use a password of C<mypass>) and notice how the roles information
+updates at the bottom of the "Book List" page. Also try the C<Logout>
+link on the book list page.
Now the "url_create" URL will work if you are already logged in as user
C<test01>, but receive an authorization failure if you are logged in as
http://localhost:3000/books/url_create/test/1/6
-while logged in as each user. Use one of the 'Logout' links (or go to
-L<http://localhost:3000/logout> in your browser directly) when you are
+while logged in as each user. Use one of the 'Logout' links (or go to
+L<http://localhost:3000/logout> in your browser directly) when you are
done.
plugin can automate much of the work required to perform role-based
authorization in a Catalyst application.
+
=head2 Add the C<Catalyst::Plugin::Authorization::ACL> Plugin
Open C<lib/MyApp.pm> in your editor and add the following plugin to the
-C<use Catalyst> statement:
+C<__PACKAGE__-E<gt>setup> statement:
Authorization::ACL
Note that the remaining C<use Catalyst> plugins from earlier sections
are not shown here, but they should still be included.
+
=head2 Add ACL Rules to the Application Class
Open C<lib/MyApp.pm> in your editor and add the following B<BELOW> the
-C<__PACKAGE__-E<gt>setup;> statement:
+C<__PACKAGE__-E<gt>setup> statement:
# Authorization::ACL Rules
__PACKAGE__->deny_access_unless(
"/books/form_create_do",
[qw/admin/],
);
- __PACKAGE__->deny_access_unless(
+ __PACKAGE__->allow_access_if(
"/books/delete",
[qw/user admin/],
);
first two rules only allow admin-level users to create new books using
the form (both the form itself and the data submission logic are
protected). The third statement allows both users and admins to delete
-books. The C</books/url_create> action will continue to be protected by
-the "manually configured" authorization created earlier in this part of
-the tutorial.
+books; letting users delete but not create book entries may sound odd in
+the "real world", but this is just an example. The C</books/url_create>
+action will continue to be protected by the "manually configured"
+authorization created earlier in this part of the tutorial.
The ACL plugin permits you to apply allow/deny logic in a variety of
ways. The following provides a basic overview of the capabilities:
=back
+
=head2 Add a Method to Handle Access Violations
By default,
following method:
=head2 access_denied
-
+
Handle Catalyst::Plugin::Authorization::ACL access denied exceptions
-
+
=cut
-
+
sub access_denied : Private {
my ($self, $c) = @_;
-
+
# Set the error message
$c->stash->{error_msg} = 'Unauthorized!';
-
+
# Display the list
$c->forward('list');
}
Log in as C<test02>. Once at the book list, click the "Create" link
to try the C<form_create> action. You should receive a red
"Unauthorized!" error message at the top of the list. (Note that in
-the example code the "Create" link code in C<root/src/books/list.tt2>
+the example code the "Admin Create" link code in C<root/src/books/list.tt2>
is inside an C<IF> statement that only displays the list to
admin-level users.) If you log in as C<test01> you should be able to
view the C<form_create> form and add a new book.
-When you are done, use one of the 'Logout' links (or go to the
+Use one of the 'Logout' links (or go to the
L<http://localhost:3000/logout> URL directly) when you are done.
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/>).