Catalystic conversion - part 4

autarch on 2007-03-03T17:24:03

So I wanted to adapt my user handling bits to work with Catalyst's Authentication plugins. I decided to go ahead and use the dev version of Catalyst::Plugin::Authentication, since this presumably will be the Catalyst way in the future.

However, there was one hitch in adapting my app's notion of a user to Catalyst's. In my app, there is always a user object, whether or not the end user has actually authenticated. Before an end user authenticates, this object is a VegGuide::User::Guest, and afterwards it's a VegGuide::User. I like this style because it means I can always count on having a user object. I find code like this rather tedious:

if ( $c->user() and $c->user()->get_object()->can_delete_entry() )
{
    ...
}


When I know that $c->user()->get_object() always returns a valid object, the code that ends up written is much clearer in its intent.

if ( $c->user()->get_object()->can_delete_entry() )
{
    ...
}


This wasn't too hard to work around. I have a controller for my root URI-space that includes an auto() method like this:

sub auto : Private
{
    my $self = shift;
    my $c    = shift;

$c->authenticate( {} ) unless $c->user();

...

return 1; }


This is a bit of a hack, but it works. Once a user has hit the site once, their user_id is stored in their session. This means that $c->user() will always return something after the first hit. If the user hasn't really authenticated, then the session will just indicate that they are a guest.

It would be nice if Catalyst::Plugin::Authentication could support this style of usage natively, maybe with a flag like "auto_authenticate" or something.

To make this work, all I need to do is implement appropriate logic in my Store plugin. If we have real credentials to use, we try to load real user, otherwise we return a guest:

sub find_user
{
    my $class = shift;
    my $auth  = shift;
    my $c     = shift;

my $user = VegGuide::User->new(%$auth) if %$auth;

$user ||= VegGuide::User::Guest->new();

return VegGuide::Plugin::Authentication::User->new($user); }


The VegGuide::Plugin::Authentication::User class provides the minimal glue needed to make Catalyst happy. I didn't want my core user data object to subclass Catalyst::Plugin::Authentication::User, which feels unclean to me. Outside of Catalyst, I don't need any of the methods that Catalyst::Plugin::Authentication::User demands, and I want to make sure that any code that isn't webapp-specific is usable without Catalyst in the mix.