[Catalyst] Extending C::Plugin::Authentication::Store::DBIC for additional constraints

Ashvin Kumar ashvin at affinitycircles.com
Mon Mar 26 09:28:36 GMT 2007


Doran L. Barton wrote:

>Not long ago, Fernan Aguero proclaimed...
>  
>
>>Certainly not what you were asking (subclassing
>>store::dbic), but  ...
>>
>>
>>sub login : Local {
>>    my ( $self, $c ) = @_; 
>>
>>    my $username = $c->req->params->{username} || ""; 
>>    my $password = $c->req->params->{password} || ""; 
>>
>>    my $model = $c->model('Users');
>>
>>    if ( $username && $password ) {
>>
>>      # attempt to login
>>      if ( $c->login( $username, $password ) ) {
>>
>>        # now we check site_id
>>        $ok = $model->search(
>>          { username => $username,
>>            password => $password,
>>            site_id  => $site_id } )->count();
>>  
>>        $c->logout unless $ok > 0;
>>
>>      }
>>    
>>
>
>This is an interesting strategy. The only thing I question is the
>$c->login() call because the username field is not unique (there could be
>more than one 'johndoe' in the table).
>
>After I posted my original question, I started wondering about
>concatenating the username and site_id together. I have a feeling this
>won't fly well inside DBIx::Class, but in theory if I declare the user
>field to be "username || '#' || site_id" and call the login() using
>$username . '#' . $c->stash->{'site_id'}, the resulting SELECT in sql would
>find the unique row. Of course, that all falls apart in the ORM, most
>likely. 
>  
>
We had a similar requirement, and came to a slightly different solution 
than proposed by Fernan. Instead of authenticating on username/password, 
we authenticated based on user_id/password where user_id is the primary 
key and guaranteed to be unique.

In the login subroutine, we pulled the user object based on the username 
param and the site_id, and then called $c->login with the user object's 
id and the password param. In code-speak:

In our setup:

__PACKAGE__->config->{ authentication }{ dbic } = {
    user_class    => 'MyModel::users'
    user_field     => 'id',        # guaranteed to be unique
    password_field => 'password',
};

Our login function:

sub login : Local {
    my ( $self, $c ) = @_;

    my $username = $c->req->params->{ username } || '';
    my $password = $c->req->params->{ password } || '';
    my $site_id  = $c->req->params->{ site_id };

    if ( $username && $password ) {
        my $user_obj = $c->model( 'MyModel::users' )->search(
            {
                username => $username,
                site_id  => $site_id,
            }
        )->first;

        if ( $user_obj && $c->login( $user_obj->id, $password ) ) {
            # user's logged in...          
        }
    }
}

This process takes an extra query since the authentication class does 
it's own query as well, but it solves the problem. I hope that helps.

Ashvin



More information about the Catalyst mailing list