The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Catalyst::Plugin::Authentication::Store::DBIC - Authentication and authorization against a DBIx::Class or Class::DBI model.

SYNOPSIS

    use Catalyst qw/
        Authentication
        Authentication::Store::DBIC
        Authentication::Credential::Password
        Authorization::Roles                                # if using roles
        /;

    # Authentication
    __PACKAGE__->config->{authentication}{dbic} = {
        user_class         => 'MyApp::Model::User',
        user_field         => 'username',
        password_field     => 'password',
        password_type      => 'hashed',
        password_hash_type => 'SHA-1',
    };

    # Authorization using a many-to-many role relationship
    # For more detailed instructions on setting up role-based auth, please
    # see the section below titled L<"Roles">.
    __PACKAGE__->config->{authorization}{dbic} = {
        role_class           => 'MyApp::Model::Role',
        role_field           => 'role',
        role_rel             => 'map_user_role',            # DBIx::Class only
        user_role_user_field => 'user',
        user_role_class      => 'MyApp::Model::UserRole',   # Class::DBI only
        user_role_role_field => 'role',                     # Class::DBI only
    };

    # log a user in
    sub login : Global {
        my ( $self, $c ) = @_;

        $c->login( $c->req->param("email"), $c->req->param("password"), );
    }

    # verify a role
    if ( $c->check_user_roles( 'admin' ) ) {
        $model->delete_everything;
    }

DESCRIPTION

This plugin uses a DBIx::Class (or Class::DBI) object to authenticate a user.

AUTHENTICATION CONFIGURATION

Authentication is configured by setting an authentication->{dbic} hash reference in your application's config method. The following configuration options are supported.

user_class

The name of the class that represents a user object. Can be the full class name, or just the model name (i.e. the part after App::Model). If it is a DBIC class, will automatically save and use the resultset from the DBIC schema.

user_field

The name of the column holding the user identifier (defaults to "user")

password_field

The name of the column holding the user's password (defaults to "password")

password_type

The type of password your user object stores. One of: clear, crypted, or hashed. Defaults to clear.

password_hash_type

If using a password_type of hashed, this option specifies the hashing method being used. Any hashing method supported by the Digest module may be used.

password_pre_salt

Use this option if your passwords are hashed with a prefix salt value.

password_post_salt

Use this option if your passwords are hashed with a postfix salt value.

auto_create_user

If this option is set, when a user is not found, an auto_create method will be called on your user_class with the arguments that were passed to get_user. If it returns true, it is assumed that a user corresponding to the arguments has been created, and the user will be looked up again.

catalyst_user_class

If using a plain Model class, which has username and password fields is not working for you, because you have more complex objects, or you need to do something else odd to fetch those values, or your role fields.. You can subclass Catalyst::Plugin::Authentication::Store::DBIC::User, and supply your class name here.

AUTHORIZATION CONFIGURATION

Role-based authorization is configured by setting an authorization->{dbic} hash reference in your application's config method. The following options are supported. For more detailed instructions on setting up roles, please see the section below titled "Roles".

role_class

The name of the class that contains the list of roles. Can be the full class name, or just the model name (i.e. the part after App::Model). If it is a DBIC class, will automatically save and use the resultset from the DBIC schema.

role_field

The name of the field in "role_class" that contains the role name.

role_rel

DBIx::Class models only. This field specifies the name of the relationship in "role_class" that refers to the mapping table between users and roles. Using this relationship, DBIx::Class models can retrieve the list of roles for a user in a single SQL statement using a join.

user_role_class

Class::DBI models only. The name of the class that contains the many-to-many linking data between users and roles.

user_role_user_field

The name of the field in "user_role_class" that contains the user ID. This is required for both DBIx::Class and Class::DBI.

user_role_role_field

Class::DBI models only. The name of the field in "user_role_class" that contains the role ID.

user_object

You can get the DBIx::Class or Class::DBI row object corresponding to the current user by calling $c->user->obj. You can also get the value of an individual column with $c->user->column_name, assuming it does not conflict with an existing method in <Catalyst::Plugin::Authentication::Store::DBIC.

Note: The earlier methods of $c->user_object and $c->user->user still work, but are no longer recommended. The new API is cleaner and easier to use.

setup_finished

Finalises the setup of the Plugin by creating and user_class and role_class that is independent of whether it is Class::DBI or DBIx::Class

INTERNAL METHODS

setup

ROLES

This section will attempt to provide detailed instructions for configuring role-based authorization in your application.

Database Schema

The basic database structure for roles consists of the following 3 tables. This syntax is for SQLite, but can be easily adapted to other databases.

    CREATE TABLE user (
        id       INTEGER PRIMARY KEY,
        username TEXT,
        password TEXT
    );

    CREATE TABLE role (
        id   INTEGER PRIMARY KEY,
        role TEXT
    );

    # DBIx::Class can handle multiple primary keys
    CREATE TABLE user_role (
        user INTEGER,
        role INTEGER,
        PRIMARY KEY (user, role)
    );

    # Class::DBI may need the following user_role table
    CREATE TABLE user_role (
        id   INTEGER PRIMARY KEY,
        user INTEGER,
        role INTEGER,
        UNIQUE (user, role)
    );

DBIx::Class

For best performance when using roles, DBIx::Class models are recommended. By using DBIx::Class you will benefit from optimized SQL using joins that can retrieve roles for a user with a single SQL statement.

The steps for setting up roles with DBIx::Class are:

1. Create Model classes and define relationships

    package MyApp::Model::DB;
    use strict;
    use base 'Catalyst::Model::DBIC::Schema';
    __PACKAGE__->config(
        schema_class => 'MyApp::Schema',
        connect_info => [ ... ],
    );
    
    1;
    
    package MyApp::Schema;
    use strict;
    use base 'DBIx::Class::Schema';
    
    __PACKAGE__->load_classes;

    1;

    package MyApp::Schema::User;
    use strict;
    use base 'DBIx::Class';

    __PACKAGE__->load_components( qw/ Core / );
    __PACKAGE__->table( 'user' );
    __PACKAGE__->add_columns( qw/id username password/ );
    __PACKAGE__->set_primary_key( 'id' );

    __PACKAGE__->has_many(
        map_user_role => 'MyApp::Schema::UserRole' => 'user' );

    1;

    package MyApp::Schema::Role;
    use strict;
    use base 'DBIx::Class';

    __PACKAGE__->load_components( qw/ Core / );
    __PACKAGE__->table( 'role' );
    __PACKAGE__->add_columns( qw/id role/ );
    __PACKAGE__->set_primary_key( 'id' );

    __PACKAGE__->has_many(
        map_user_role => 'MyApp::Schema::UserRole' => 'role' );

    1;

    package MyApp::Model::UserRole;
    use strict;
    use base 'DBIx::Class';

    __PACKAGE__->load_components( qw/ Core / );
    __PACKAGE__->table( 'user_role' );
    __PACKAGE__->add_columns( qw/user role/ );
    __PACKAGE__->set_primary_key( qw/user role/ );

    1;

2. Specify authorization configuration settings

For the above DBIx::Class model classes, the configuration would look like this:

    __PACKAGE__->config->{authorization}{dbic} = {
        role_class           => 'DB::Role',
        role_field           => 'role',
        role_rel             => 'map_user_role',
        user_role_user_field => 'user',
    };

Class::DBI

Class::DBI models are also supported but require slightly more configuration. Performance will also suffer as more SQL statements must be run to retrieve all roles for a user.

The steps for setting up roles with Class::DBI are:

1. Create Model classes

    package MyApp::Model::CDBI;
    use strict;
    use base 'Class::DBI';
    __PACKAGE__->connection(...);

    package MyApp::Model::User;
    use strict;
    use base 'MyApp::Model::CDBI';

    __PACKAGE__->table  ( 'user' );
    __PACKAGE__->columns( Primary   => qw/id/ );
    __PACKAGE__->columns( Essential => qw/username password/ );

    1;

    package MyApp::Model::Role;
    use strict;
    use base 'MyApp::Model::CDBI';

    __PACKAGE__->table  ( 'role' );
    __PACKAGE__->columns( Primary   => qw/id/ );
    __PACKAGE__->columns( Essential => qw/role/ );

    1;

    package MyApp::Model::UserRole;
    use strict;
    use base 'MyApp::Model::CDBI';

    __PACKAGE__->table  ( 'user_role' );
    __PACKAGE__->columns( Primary   => qw/id/ );
    __PACKAGE__->columns( Essential => qw/user role/ );

    1;

2. Specify authorization configuration settings

For the above Class::DBI model classes, the configuration would look like this:

    __PACKAGE__->config->{authorization}{dbic} = {
        role_class           => 'MyApp::Model::Role',
        role_field           => 'role',
        user_role_class      => 'MyApp::Model::UserRole',
        user_role_user_field => 'user',
        user_role_role_field => 'role',
    };

SEE ALSO

Catalyst::Plugin::Authentication, Catalyst::Plugin::Authorization::Roles

AUTHORS

David Kamholz, <dkamholz@cpan.org>

Andy Grundman

COPYRIGHT

This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself.