Update

The new Authentication tutorial is now available on CPAN. The Authorization tutorial is also on CPAN. Please use that instead of the example below.

The most up-to-date version is always on SVN. Use pod2html from your Perl's bin directory to convert it to HTML.

Authentication and authorization example

If you are implementing authentication and authorization in your Catalyst application, you may be having some difficulty recently. Authentication and Authorization is now implemented differently than is shown in the Catalyst::Manual::Tutorial (5.701003). Until related documentation has been updated, I hope that this will help you apply authentication and authorization to your own application.

This is not a full fledged tutorial and I do not presume to have a high level knowledge of all related components. What I am presenting here, however, is what worked for me. For familiarity, I'm basing this example directly on the MyApp tutorial from the Catalyst::Manual documentation. So, if you are familiar with that then the changes here should be clear and easily carried over into your own custom application as needed.

As always, feel free to request additional help in #catalyst, which is where I received the help I needed to implement this myself. My hope is that my presentation here is adequate enough that you will be able to implement this on your own with little stress. Only a few small changes are needed.

In short, the changes consist of the following:

  • Add a many_to_many relationship to your Users class.
  • Reconfigure your myapp.yml configuration.
  • Remove Authentication::Store::DBIC / Authentication::Credential::Password from MyApp.pm

See the brief list of suggested reading material (cpan docs) at the end of this document.

Database

First, if you follow the Authentication tutorial's example, you have a database like the following.

 CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT, email_address TEXT, first_name TEXT, last_name TEXT, active INTEGER);


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

 CREATE TABLE user_roles (user_id INTEGER, role_id INTEGER, PRIMARY KEY (user_id, role_id));

You do not need to alter anything in your database.

Classes

If you've created your DBIx schema according to the same documentation, it should result in the following classes.

User class

package MyAppDB::User;

use base qw/DBIx::Class/;

__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('users');
__PACKAGE__->add_columns(qw/id username password email_address first_name last_name/);
__PACKAGE__->set_primary_key('id');


__PACKAGE__->has_many(map_user_role => 'MyAppDB::UserRole', 'user_id');

1;

The only thing you will need to change in your User class is to add a second relationship below has_many. This new line will be a many_to_many relationship that says User can have many Roles and they will be identified by the role field in the map_user_roles relation. So, add the following:

__PACKAGE__->many_to_many( roles => 'map_user_role', 'role' );

Role class

package MyAppDB::Role;

use base qw/DBIx::Class/;

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

__PACKAGE__->has_many(map_user_role => 'MyAppDB::UserRole', 'role_id');

1;

Nothing needs to change in your Role class.

UserRole class

package MyAppDB::UserRole;

use base qw/DBIx::Class/;

__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('user_roles');
__PACKAGE__->add_columns(qw/user_id role_id/);
__PACKAGE__->set_primary_key(qw/user_id role_id/);


__PACKAGE__->belongs_to(user => 'MyAppDB::User', 'user_id');
__PACKAGE__->belongs_to(role => 'MyAppDB::Role', 'role_id');

1;

Nothing needs to be changed in your UserRole class.

MyApp.pm

Your MyApp.pm should currently include the following:

use Catalyst qw/
    . . .
    Authentication
    Authentication::Store::DBIC
    Authentication::Credential::Password

    Authorization::Roles
    Authorization::ACL
    . . .
    /;

You can change this to read as follows:

use Catalyst qw/
    . . .
    Authentication

    Authorization::Roles
    Authorization::ACL
    . . .
    /;

myapp.yml

If you stored your configuration in YAML (myapp.yml), it probably includes the following:

authentication:
    dbic:
        user_class: MyAppDB::User
        user_field: username
        password_field: password

authorization:
    dbic:
        role_class: MyAppDB::Role
        role_field: role
        role_rel: map_user_role
        user_role_user_field: user_id

You'll need to change it to look like the following. Notice that configuration is no longer stored under authentication->dbic and authorization->dbic, but that the authorization details are now placed under authentication->realms->default->store. Also note that some of the fields have changed slightly. (Do not copy and paste the YAML content as proper indentation is crucial).

authentication:
    realms:
        default:
            credential:
                class: Password
                password_field: password
                password_type: clear
            store:
                class: DBIx::Class
                user_class: DB::User
                id_field: id
                role_relation: roles
                role_field: role

In this new YAML configuration...

  • user_class

    refers to MyAppDB::User, up above.

  • id_field

    The field your user is identified by in your Users table.

  • role_relation

    The name of the the many_to_many relationship we defined in MyAppDB::User

  • role_field

    The name of the field in the Roles table that identifies the text names of your roles (ie 'admin').

Suggested reading

My tags:
 
Popular tags:
 
Powered by Catalyst
Powered by MojoMojo Hosted by Shadowcat - Managed by Nordaaker