X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FTutorial%2FAuthorization.pod;h=e1d54969ad0029c0e4b1038dc169ca6cdf873dd8;hb=c3cf3bc32d1fb13139827cd81749413e5b724111;hp=867c26ec5afa0f0a660a436ba37588a2503a7978;hpb=533fee734b6738d009dd5405dda9501e430a4e9f;p=catagits%2FCatalyst-Manual.git
diff --git a/lib/Catalyst/Manual/Tutorial/Authorization.pod b/lib/Catalyst/Manual/Tutorial/Authorization.pod
index 867c26e..e1d5496 100644
--- a/lib/Catalyst/Manual/Tutorial/Authorization.pod
+++ b/lib/Catalyst/Manual/Tutorial/Authorization.pod
@@ -1,11 +1,11 @@
=head1 NAME
-Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Part 6: Authorization
+Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Chapter 6: Authorization
=head1 OVERVIEW
-This is B for the Catalyst tutorial.
+This is B for the Catalyst tutorial.
L
@@ -56,11 +56,12 @@ L
=head1 DESCRIPTION
-This part of the tutorial adds role-based authorization to the existing
-authentication implemented in Part 5. It provides simple examples of
-how to use roles in both TT templates and controller actions. The first
-half looks at manually configured authorization. The second half looks
-at how the ACL authorization plugin can simplify your code.
+This chapter of the tutorial adds role-based authorization to the
+existing authentication implemented in Chapter 5. It provides simple
+examples of how to use roles in both TT templates and controller
+actions. The first half looks at basic authorization concepts. The
+second half looks at how moving your authorization code to your model
+can simplify your code and make things easier to maintain.
You can checkout the source code for this example from the catalyst
subversion repository as per the instructions in
@@ -69,80 +70,33 @@ L.
=head1 BASIC AUTHORIZATION
-In this section you learn how to manually configure authorization.
+In this section you learn the basics of how authorization works under
+Catalyst.
=head2 Update Plugins to Include Support for Authorization
Edit C and add C to the list:
- __PACKAGE__->setup(qw/
- -Debug
- ConfigLoader
- Static::Simple
-
- StackTrace
-
- Authentication
- Authorization::Roles
-
- Session
- Session::Store::FastMmap
- Session::State::Cookie
- /;
+ # Load plugins
+ use Catalyst qw/-Debug
+ ConfigLoader
+ Static::Simple
+
+ StackTrace
+
+ Authentication
+ Authorization::Roles
+
+ 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 can put the plugins in the C
@@ -176,7 +131,7 @@ This code displays a different combination of links depending on the
roles assigned to the user.
-=head2 Limit C to C Users
+=head2 Limit Books::add to 'admin' Users
C statements in TT templates simply control the output that is sent
to the user's browser; it provides no real enforcement (if users know or
@@ -195,7 +150,7 @@ updating C to match the following code:
=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 "// to match the following code:
# 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!');
}
}
@@ -244,12 +199,12 @@ way to demonstrate that TT templates will not be used if the response
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).
+Chapter 3 or C to an action that shows an "unauthorized" page).
B: If you want to keep your existing C 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 and C<=end> after the closing C<}>.
+Pod comment. For example, put something like C<=begin> before
+C and C<=end> after the closing C<}>.
=head2 Try Out Authentication And Authorization
@@ -261,10 +216,10 @@ running) and restart it:
Now trying going to L and you should
be taken to the login page (you might have to C or
-C your browser and/or click the "Logout" link on the book
+C your browser and/or click the "User Logout" link on the book
list page). Try logging in with both C and C (both
use a password of C) and notice how the roles information
-updates at the bottom of the "Book List" page. Also try the C
+updates at the bottom of the "Book List" page. Also try the "User Logout"
link on the book list page.
Now the "url_create" URL will work if you are already logged in as user
@@ -273,146 +228,124 @@ C. Try:
http://localhost:3000/books/url_create/test/1/6
-while logged in as each user. Use one of the 'Logout' links (or go to
+while logged in as each user. Use one of the "logout" links (or go to
L in your browser directly) when you are
done.
-=head1 ENABLE ACL-BASED AUTHORIZATION
-
-This section takes a brief look at how the
-L
-plugin can automate much of the work required to perform role-based
-authorization in a Catalyst application.
-
-
-=head2 Add the C Plugin
-
-Open C in your editor and add the following plugin to the
-C<__PACKAGE__-Esetup> statement:
-
- Authorization::ACL
-
-Note that the remaining C plugins from earlier sections
-are not shown here, but they should still be included.
-
-
-=head2 Add ACL Rules to the Application Class
-
-Open C in your editor and add the following B the
-C<__PACKAGE__-Esetup> statement:
-
- # Authorization::ACL Rules
- __PACKAGE__->deny_access_unless(
- "/books/form_create",
- [qw/admin/],
- );
- __PACKAGE__->deny_access_unless(
- "/books/form_create_do",
- [qw/admin/],
- );
- __PACKAGE__->deny_access_unless(
- "/books/delete",
- [qw/user admin/],
- );
-
-Each of the three statements above comprises an ACL plugin "rule". The
-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 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:
-
-=over 4
-
-=item *
-
-The ACL plugin only operates on the Catalyst "private namespace". You
-are using the private namespace when you use C actions. C,
-C, and C allow you to specify actions where the path and
-the namespace differ -- the ACL plugin will not work in these cases.
-
-=item *
-
-Each rule is expressed in a separate
-C<__PACKAGE__-Edeny_access_unless()> or
-C<__PACKAGE__-Eallow_access_if()> line (there are several other
-methods that can be used for more complex policies, see the C
-portion of the
-L
-documentation for more details).
-
-=item *
-
-Each rule can contain multiple roles but only a single path.
-
-=item *
-
-The rules are tried in order (with the "most specific" rules tested
-first), and processing stops at the first "match" where an allow or deny
-is specified. Rules "fall through" if there is not a "match" (where a
-"match" means the user has the specified role). If a "match" is found,
-then processing stops there and the appropriate allow/deny action is
-taken.
-
-=item *
-
-If none of the rules match, then access is allowed.
+=head1 ENABLE MODEL-BASED AUTHORIZATION
-=item *
+Hopefully it's fairly obvious that adding detailed permission checking
+logic to our controllers and view templates isn't a very clean or
+scalable way to build role-based permissions into out application. As
+with many other aspects of MVC web development, the goal is to have
+your controllers and views be an "thin" as possible, with all of the
+"fancy business logic" built into your model.
-The rules currently need to be specified in the application class
-C B the C<__PACKAGE__-Esetup;> line.
-
-=back
+For example, let's add a method to our C Result Class to
+check if a user is allowed to delete a book. Open
+C and add the following method
+(be sure to add it below the "C" line):
+ =head2 delete_allowed_by
+
+ Can the specified user delete the current book?
+
+ =cut
+
+ sub delete_allowed_by {
+ my ($self, $user) = @_;
+
+ # Only allow delete if user has 'admin' role
+ return $user->has_role('admin');
+ }
-=head2 Add a Method to Handle Access Violations
+Here we call a C method on our user object, so we should add
+this method to our Result Class. Open
+C and add the following method below
+the "C" line:
-By default,
-L
-throws an exception when authorization fails. This will take the user
-to the Catalyst debug screen, or a "Please come back later" message if
-you are not using the C<-Debug> flag. This step uses the
-C method in order to provide more appropriate feedback to
-the user.
+ =head 2 has_role
+
+ Check if a user has the specified role
+
+ =cut
+
+ use Perl6::Junction qw/any/;
+ sub has_role {
+ my ($self, $role) = @_;
+
+ # Does this user posses the required role?
+ return any(map { $_->role } $self->roles) eq $role;
+ }
-Open C in your editor and add the
-following method:
+Now we need to add some enforcement inside our controller. Open
+C and update the C method to
+match the following code:
- =head2 access_denied
+ =head2 delete
- Handle Catalyst::Plugin::Authorization::ACL access denied exceptions
+ Delete a book
=cut
- sub access_denied : Private {
+ sub delete :Chained('object') :PathPart('delete') :Args(0) {
my ($self, $c) = @_;
- # Set the error message
- $c->stash->{error_msg} = 'Unauthorized!';
+ # Check permissions
+ $c->detach('/error_noperms')
+ unless $c->stash->{object}->delete_allowed_by($c->user->get_object);
- # Display the list
- $c->forward('list');
+ # Use the book object saved by 'object' and delete it along
+ # with related 'book_authors' entries
+ $c->stash->{object}->delete;
+
+ # Use 'flash' to save information across requests until it's read
+ $c->flash->{status_msg} = "Book deleted";
+
+ # Redirect the user back to the list page
+ $c->response->redirect($c->uri_for($self->action_for('list')));
+ }
+
+Here, we C to an error page if the user is lacking the
+appropriate permissions. For this to work, we need to make
+arrangements for the '/error_noperms' action to work. Open
+C and add this method:
+
+ =head2 error_noperms
+
+ Permissions error screen
+
+ =cut
+
+ sub error_noperms :Chained('/') :PathPath('error_noperms') :Args(0) {
+ my ($self, $c) = @_;
+
+ $c->stash->{template} = 'error_noperms.tt2';
}
+And also add the template file by putting the following text into
+C:
+
+ Permission Denied
+
Then run the Catalyst development server script:
$ script/myapp_server.pl
-Log in as C. Once at the book list, click the "Create" link
-to try the C 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
-is inside an C statement that only displays the list to
-admin-level users.) If you log in as C you should be able to
-view the C form and add a new book.
+Log in as C and create several new books using the C
+feature:
+
+ http://localhost:3000/books/url_create/Test/1/4
+
+Then, while still logged in as C, click the "Delete" link next
+to one of these books. The book should be removed and you should see
+the usual green "Book deleted" message. Next, click the "User Logout"
+link and log back in as C. Now try deleting one of the books.
+You should be taken to the red "Permission Denied" message on our
+error page.
-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 URL directly) when you are done.