[Catalyst] Authentication not working as expected

Mike Raynham catalyst at mikeraynham.co.uk
Tue Jan 11 17:18:39 GMT 2011


On 11/01/11 16:09, Ben Lavery wrote:
> Dear all,
>
> After installing Catalyst on an OpenIndiana virtual machine, I've been working through the Definitive Guide to Catalyst for the last few weeks and have been impressed with how smoothly most of it has gone.
>
> I have, however, become unstuck at Chapter 6.  The book explains how to create an application that uses some simple CRUD with user and role data, and uses authentication to prevent users updating other user's data.
> I have a working application that allows one to create and read user data, but I can't figure out how to apply the authentication.  The book says:
> "When using the Authentication plug-in, as we showed in Chapter 3..."
>
> I've gone back to Chapter 3 and followed the steps, but I'm not sure where I am supposed to put the "$c->authenticate".
> If I place it in DBAuthTest::Controller::Root in a subroutine called "auto", every page on the site needs me to log in, but no matter what I put in the username and password fields it says that the data is invalid.
> As such I have no idea where I have gone wrong, after Googling I can't find similar problems, or people who have had similar problems or implemented a similar system in a similar way.
> I have looked at the source code provided on the publisher's site, but it doesn't include code for the whole chapter, and indeed seems to stop given code a page or two previous to where I am now...
>
> I have uploaded a copy of my application to http://hashbang0.com/personal/DBAuthTest.tar.bz2 (~46K) which I hope help demonstrate where I am currently.
>
> Many thanks for your time, I appreciate any help you can give,
>
> Ben Lavery

The authentication section of the online tutorial, as suggested by 
Hernan Lopes, is definitely worth reading.  However, what follows may 
get you started.  The following approach doesn't deal with roles or 
permission levels - it just tests if a user is logged in or not.

The following code is just to give you an idea of how it would work. 
I've just grabbed bits of code from various places and stuck them 
together, so please don't expect to be able to just copy and paste it 
into your code :-)

In your secure controller actions, you need to check if a user is logged in:

In DBAuthTest::Controller::AuthUsers...

###

sub add : Chained('base'): PathPart('add'): Args(0) {
     my ($self, $c) = @_;

     # Detach to the no_user action if a user is not logged in.
     $c->detach( '/no_user' ) unless $c->user_exists;

     # Do secure stuff here...
}

###

Then in DBAuthTest::Controller::Root...

###

sub no_user :Chained('/') :PathPart :Args(0) {
     my ($self, $c) = @_;
	
     # The user is not logged in.

     # Remember the failed action so that we can redirect to it
     # after login.
     $c->session->{action_private_path} = $c->action->private_path;

     # Put a message in the flash so that we can display it on the
     # login page.
     $c->flash(
         error_msg =>
             'To perform the requested action, you must be logged in.'
     );

     # Redirect to a login page.
     $c->response->redirect(
         $c->uri_for_action( '/login' )
     );
}

###

You then need a suitable controller to handle authentication:

###

package DBAuthTest::Controller::Login;

sub login :Chained('base') :PathPart('login') :Args(0) {
     my ( $self, $c ) = @_;

     # Get username and password from somewhere...
     my $username = $c->request->params->{username};
     my $password = $c->request->params->{password};

     # Do something here if username and password have
     # not been supplied.
	
     unless ( $c->authenticate( {
         username => $username,
	password => $password
     } ) ) {

         # Stash an error message.
         $c->stash(
             error_msg => 'Incorrect username, password, or both',
         );

         # Handle invalid credentials.

         return;
     }

     if( $c->session->{action_private_path} ) {

         # Redirect to the previously unauthorised action.
         $c->response->redirect(
             $c->uri_for_action( $c->session->{action_private_path} )
         );

         delete $c->session->{action_private_path};

     } else {

         # Redirect to a default page.
         $c->response->redirect( $c->uri_for_action('/index') );

     }
}

###




More information about the Catalyst mailing list