foreach step of path {
+ ->require_auth (hook)
+ # exits nav_loop if true
+
->morph
# check ->allow_morph
# check ->allow_nested_morph
# Assuming /cgi-bin/my_app is the program being run
- URI: /cgi-bin/my_app
+ URI: /cgi-bin/my_app
STEP: main
FORM: {}
WHY: No other information is passed. The path method is
called which eventually calls ->default_step which
defaults to "main"
- URI: /cgi-bin/my_app?foo=bar
+ URI: /cgi-bin/my_app?foo=bar
STEP: main
FORM: {foo => "bar"}
WHY: Same as previous example except that QUERY_STRING
information was passed and placed in form.
- URI: /cgi-bin/my_app?step=my_step
+ URI: /cgi-bin/my_app?step=my_step
STEP: my_step
FORM: {step => "my_step"}
WHY: The path method is called which looks in $self->form
for the key ->step_key (which defaults to "step").
- URI: /cgi-bin/my_app?step=my_step&foo=bar
+ URI: /cgi-bin/my_app?step=my_step&foo=bar
STEP: my_step
FORM: {foo => "bar", step => "my_step"}
- WHY: Same as before but has other parameters were passed.
+ WHY: Same as before but another parameter was passed.
- URI: /cgi-bin/my_app/my_step
+ URI: /cgi-bin/my_app/my_step
STEP: my_step
FORM: {step => "my_step"}
WHY: The path method is called which called path_info_map_base
$self->form->{$self->step_key} for the initial step. See
the path_info_map_base method for more information.
- URI: /cgi-bin/my_app/my_step?foo=bar
+ URI: /cgi-bin/my_app/my_step?foo=bar
STEP: my_step
FORM: {foo => "bar", step => "my_step"}
WHY: Same as before but other parameters were passed.
- URI: /cgi-bin/my_app/my_step?step=other_step
+ URI: /cgi-bin/my_app/my_step?step=other_step
STEP: other_step
FORM: {step => "other_step"}
WHY: The same procedure took place, but when the PATH_INFO
];
}
- URI: /cgi-bin/my_app/my_step/bar
+ URI: /cgi-bin/my_app/my_step/bar
STEP: my_step
FORM: {foo => "bar"}
WHY: The step was matched as in previous examples using
and the corresponding matched value was placed into
the form using the keys specified following the regex.
- URI: /cgi-bin/my_app/my_step/bar/1234
+ URI: /cgi-bin/my_app/my_step/bar/1234
STEP: my_step
FORM: {foo => "bar", id => "1234"}
WHY: Same as the previous example, except that the first
order that will match the most data. The third regex
would also match this PATH_INFO.
- URI: /cgi-bin/my_app/my_step/some/other/type/of/data
+ URI: /cgi-bin/my_app/my_step/some/other/type/of/data
STEP: my_step
FORM: {anything_else => 'some/other/type/of/data'}
WHY: Same as the previous example, except that the third
regex matched.
- URI: /cgi-bin/my_app/my_step/bar?bling=blang
+ URI: /cgi-bin/my_app/my_step/bar?bling=blang
STEP: my_step
FORM: {foo => "bar", bling => "blang"}
- WHY: Same as the first step, but additional QUERY_STRING
+ WHY: Same as the first sample, but additional QUERY_STRING
information was passed.
- URI: /cgi-bin/my_app/my_step/one%20two?bar=three%20four
+ URI: /cgi-bin/my_app/my_step/one%20two?bar=three%20four
STEP: my_step
FORM: {anything_else => "one two", bar => "three four"}
WHY: The third path_info_map regex matched. Note that the
The default hash_validation hook returns an empty hashref. This means that passed
in data is all valid and the script will automatically call the step's finalize method.
-The following shows how to some contrived validation to a step called "my_step".
+The following shows how to add some contrived validation to a step called "my_step".
sub my_step_hash_validation {
return {
The default file_print hook will look for content on your file system,
but it can also be completely overridden to return a reference to a
-scalar containing the contents of your file. Actually it can return
+scalar containing the contents of your file (beginning with version 2.14
+string references can be cached which makes templates passed this way
+"first class" citizens). Actually it can return
anything that Template::Alloy (Template::Toolkit compatible) will
treat as input. This templated html is displayed to the user during
any step that enters the "print" phase.
debug: admin/Recipe.pm line 14
shift->dump_history = [
"Elapsed: 0.00562",
+ "view - require_auth - require_auth - 0.00001 - 0",
"view - run_step - run_step - 0.00488 - 1",
" view - pre_step - pre_step - 0.00003 - 0",
" view - skip - view_skip - 0.00004 - 0",
=item get_valid_auth (method)
-If require_auth is true at either the application level or at the
-step level, get_valid_auth will be called.
+If require_auth hook returns true on any given step then get_valid_auth will be called.
It will call auth_args to get some default args to pass to
CGI::Ex::Auth->new. It augments the args with sensible defaults that
=item navigate_authenticated (method)
-Same as the method navigate but sets require_auth(1) before
-running. See the require_auth method.
+Same as the method navigate but calls ->require_auth(1) before
+running. It will only work if the navigate_authenticated method
+has not been overwritten. See the require_auth method.
=item new (class method)
Arguments are the steps used to replace. Can be called any time.
Replaces the remaining steps (if any) of the current path.
-=item require_auth (method)
+=item require_auth (hook)
-Default undef. Can return either a true value or a hashref of step names.
+Defaults to self->{require_auth} which defaults to undef.
+If called as a method and passed a single value of 1, 0, or undef it will
+set the value of $self->{require_auth} to that value. If set to a true
+value then any subsequent step will require authentication (unless its
+hook has been overwritten).
-If a hashref of stepnames is returned, authentication will be turned on
-at the step level. In this mode if any step is accessed, the get_valid_auth
-method will be called. If it fails, then the nav_loop will be stopped
-(the post_navigate method will be called - use the is_authed method to perform
-different functions). Any step of the path not in the hash will not require
-authentication. For example, to add authentication to add authentication
-to the add, edit and delete steps you could do:
+Any of the following ways can be used to require authentication on
+every step.
- sub require_auth { {add => 1, edit => 1, delete => 1} }
+=over 4
-If a non-hash true value is returned from the require_auth method then
-authentication will take place before the pre_navigation or the nav_loop methods.
-If authentication fails the navigation process is exited (the post_navigate
-method will not be called).
+=item
sub require_auth { 1 }
-Alternatively you can also could do either of the following:
+=item
__PACKAGE__->navigate_authenticated; # instead of __PACKAGE__->navigate;
- # OR
+=item
+
+ __PACKAGE__->new({require_auth => 1}->navigate;
+
+=item
sub init { shift->require_auth(1) }
- # OR
+=back
- __PACKAGE__->new({require_auth => 1}->navigate;
+Because it is called as a hook, the current step is passed as the
+first argument. If the hook returns false, no authentication will be
+required on this step. If the hook returns a true, non-hashref value,
+authentication will be required via the get_valid_auth method. If the
+method returns a hashref of stepnames to require authentication on,
+the step will require authentication via the get_valid_auth method if
+the current step is in the hashref. If authentication is required and
+succeeds, the step will proceed. If authentication is required and
+fails at the step level the current step will be aborted,
+authentication will be asked for (the post_navigate method will still
+be called).
+
+For example you could add authentication to the add, edit, and delete
+steps in any of the following ways:
-If get_valid_auth returns true, in either case, the is_authed method will
-return true and the auth_data will contain the authenticated user's data.
-If it returns false, auth_data may possibly contain a defined but false
-data object with details as to why authentication failed.
+=over 4
-See the get_valid_auth method.
+=item
+
+ sub require_auth { {add => 1, edit => 1, delete => 1} }
+
+=item
+
+ sub add_require_auth { 1 }
+ sub edit_require_auth { 1 }
+ sub delete_require_auth { 1 }
+
+=item
+
+ sub require_auth {
+ my ($self, $step) = @_;
+ return 1 if $step && $step =~ /^(add|edit|delete)$/;
+ return 0;
+ }
+
+=back
+
+If however you wanted to require authentication on all but one or two methods
+(such as requiring authentication on all but a forgot_password step) you could do
+either of the following:
+
+=over 4
+
+=item
+
+ sub require_auth {
+ my ($self, $step) = @_;
+ return 0 if $step && $step eq 'forgot_password';
+ return 1; # require auth on all other steps
+ }
+
+=item
+
+ sub require_auth { 1 } # turn it on for all steps
+
+ sub forgot_password_require_auth { 0 } # turn it off
+
+=back
+
+See the get_valid_auth method for what occurs should authentication be required.
+
+There is one key difference from the 2.14 version of App. In 2.14 and
+previous versions, the pre_navigate and post_navigate methods would
+not be called if require_auth returned a true non-hashref value. In
+version 2.15 and later, the 2.15 pre_navigate and post_navigate
+methods are always called - even if authentication fails. Also in 2.15
+and later, the method is called as a hook meaning the step is passed in.
=item run_hook (method)
return 0;
}
- my $s = "UPDATE recipe SET title = ?, ingredients = ?, directions = ? WHERE id = ?";
+ $s = "UPDATE recipe SET title = ?, ingredients = ?, directions = ? WHERE id = ?";
$self->dbh->do($s, {}, $form->{'title'},
$form->{'ingredients'},
$form->{'directions'},
sub require_auth { {add => 1, edit => 1, delete => 1} }
+We could also enable authentication by using individual hooks as in:
+
+ sub add_require_auth { 1 }
+ sub edit_require_auth { 1 }
+ sub delete_require_auth { 1 }
+
+Or we could require authentication on everything - but let a few steps in:
+
+ sub require_auth { 1 } # turn authentication on for all
+ sub main_require_auth { 0 } # turn it off for main and view
+ sub view_require_auth { 0 }
+
That's it. The add, edit, and delete steps will now require authentication.
See the require_auth, get_valid_auth, and auth_args methods for more information.
Also see the L<CGI::Ex::Auth> perldoc.
The following corporation and individuals contributed in some part to
the original versions.
- Bizhosting.com - giving a problem that fit basic design patterns.
+ Bizhosting.com - giving a problem that fit basic design patterns.
+
+ Earl Cahill - pushing the idea of more generic frameworks.
- Earl Cahill - pushing the idea of more generic frameworks.
+ Adam Erickson - design feedback, bugfixing, feature suggestions.
- Adam Erickson - design feedback, bugfixing, feature suggestions.
+ James Lance - design feedback, bugfixing, feature suggestions.
- James Lance - design feedback, bugfixing, feature suggestions.
+ Krassimir Berov - feedback and some warnings issues with POD examples.
=head1 AUTHOR