Tuesday 16 January 2024

Login System using perl catalyst MVC



1.install the required Below dependencies:

cpanm --installdeps .


2.Create a new directory for your project and create the following files:

config.yml: configuration file for your application

MyApp.pm: main application class

Model/User.pm: model class for users

View/HTML.pm: view class for rendering HTML templates

Controller/User.pm: controller class for handling user requests

public/index.html: entry point for the application


3.Here's an example config.yml file:

---

database:

  host: localhost

  port: 5432

  username: myuser

  password: mypassword

  database: mydb

server:

  host: localhost

  port: 8080

This configures our database connection and server settings.


4. In MyApp.pm, we define our application class:

package MyApp;

use strict;

use warnings;

use base 'Catalyst';

__PACKAGE__->config(

    'Database', {

        'dsn' => 'DBI:Pg:host=localhost;port=5432;username=myuser;password=mypassword;database=mydb',

    },

);

__PACKAGE__->setup_logging();

sub startup {

    my ($self) = @_;

}

sub shutdown {

    my ($self) = @_;

}

1;

Here, we inherit from the Catalyst framework and configure our database connection using the config method. We also define two methods, startup and shutdown, which will be called when the application starts and stops respectively.


5. In Model/User.pm, we define our user model class:

package MyApp::Model::User;

use strict;

use warnings;

use base 'Catalyst::Model';

__PACKAGE__->table('users');

__PACKAGE__->add_columns(

    id => {

        data_type => 'integer',

        serial   => 1,

    },

    name => {

        data_type => 'varchar',

    },

    email => {

        data_type => 'varchar',

    },

);

sub find_by_name {

    my ($self, $name) = @_;

    return $self->search({ name => $name });

}

1;

Here, we define a table named users with columns id, name, and email. We also add a method find_by_name that allows us to retrieve a user by their name.


6. In View/HTML.pm, we define our view class:

package MyApp::View::HTML;

use strict;

use warnings;

use base 'Catalyst::View';

sub render {

    my ($self, $c) = @_;

    my $template = $c->model('HTML')->render($c->req->params->{template});

    return $template->render($c->stash);

}

1;

Here, we define a view class that renders HTML templates using the render method. The template names are passed as parameters in the URL.


7. In Controller/User.pm, we define our controller class:

package MyApp::Controller::User;

use strict;

use warnings;

use base 'Catalyst::Controller';

sub index : Path('/') {

    my ($self, $c) = @_;

    my $user = $c->model('User')->find_by_name($c->req->param('name'));

    $c->res->body("Hello, $user->name!");

    $c->res->status(200);

}

sub create : Post('/create') {

    my ($self, $c) = @_;

    my $user = $c->model('User')->new();

    $user->name($c->req->param('name'));

    $user->email($c->req->param('email'));

    $user->insert();

    $c->res->redirect('/');

}

sub edit : Get('/edit/:id') {

my ($self, $c) = @_;

my $id = $c->req->param('id');

my $user = $c->model('User')->find($id);

$c->stash->{user} = $user;

$c->res->redirect('/edit');

}

sub update : Put('/edit/:id') {

my ($self, $c) = @_;

my $id = $c->req->param('id');

my $user = $c->stash->{user};

$user->name($c->req->param('name'));

$user->email($c->req->param('email'));

$user->update();

$c->res->redirect('/');

}

sub delete : Delete('/:id') {

my ($self, $c) = @_;

my $id = $c->req->param('id');

my $user = $c->model('User')->find($id);

$user->delete();

$c->res->redirect('/');

}

1;


Here, we define three additional methods: `edit`, `update`, and `delete`. The `edit` method redirects to the `/edit` route and passes the user object to the stash. The `update` method updates the user object with the new values and redirects to the root route. The `delete` method deletes the user object and redirects to the root route.


Finally, we can create routes for our application:

# /users

sub Users : Path('/users') {

my ($self, $c) = @_;

my @users = $c->model('User')->all();

$c->res->body(@users);

$c->res->status(200);

}


# /users/create

sub UserCreate : Path('/users/create') {

my ($self, $c) = @_;

$c->res->body("Create User");

$c->res->status(200);

}


# /users/:id

sub UserShow : Path('/users/:id') {

my ($self, $c) = @_;

my $id = $c->req->param('id');

my $user = $c->model('User')->find($id);

$c->res->body($user->name());

$c->res->status(200);

}


# /users/:id/edit

sub UserEdit : Path('/users/:id/edit') {

my ($self, $c) = @_;

my $id = $c->req->param('id');

my $user = $c->stash->{user};

$c->res->body("Edit User");

$c->res->status(200);

}


# /users/:id/update

sub UserUpdate : Path('/users/:id/update') {

my ($self, $c) = @_;

my $id = $c->req->param('id');

my $user = $c->stash->{user};

$user->name($c->req->param('name'));

$user->email($c->req->param('email'));

$user->update();

$c->res->redirect('/');

}


# /users/:id/delete

sub UserDelete : Path('/users/:id/delete') {

my ($self, $c) = @_;

my $id = $c->req->param('id');

my $user = $c->model('User')->find($id);

$user->delete();

$c->res->redirect('/');

}

1;


Here, we define six routes:

/users lists all users.

/users/create creates a new user.

/users/:id shows a single user.

/users/:id/edit edits a single user.

/users/:id/update updates a single user.

/users/:id/delete deletes a single user.

You now have a basic CRUD application using Catalyst and DBIx::Class. Of course, this is just a starting point, and you would likely want to add more features such as authentication, input validation, and error handling.


Creating a form to enter user information

Next, we need to create a form that allows the user to enter their information. We'll use the Form module provided by Catalyst to create a form.

In the Users controller, add the following code:

sub create : Post('/users/create') {

    my ($self, $c) = @_;

    # Create a new user object

    my $user = $c->model('User')->new();

    # Define the form fields

    my @fields = (

        'name' => {

            type => 'text',

            label => 'Name',

            size => 30,

        },

        'email' => {

            type => 'text',

            label => 'Email',

            size => 30,

        },

    );

    # Render the form

    my $form = $c->form->new(\@fields);

    $c->res->body($form->render);

    $c->res->status(200);

}

This code defines a new subroutine called create that handles the POST request to /users/create. It creates a new User object and defines an array of form fields using the @fields array. Finally, it renders the form using the $c->form->new() method and sets the HTTP status code to 200.

Now, let's create the form template in the views/users/create.tt file:

<form action="/users/create" method="post">

    <label for="name">Name:</label>

    <input type="text" id="name" name="name">

    <label for="email">Email:</label>

    <input type="text" id="email" name="email">

    <input type="submit" value="Create User">

</form>

This template contains a simple form with two input fields for the user's name and email address, and a submit button. The action attribute specifies the URL to post the form data to, which in this case is /users/create.

Handling form submissions

Now that we have created the form, we need to handle the form submission. We'll use the process method provided by the Catalyst::Form module to process the form data.

Add the following code to the Users controller:

sub create : Post('/users/create') {

    my ($self, $c) = @_;

    # Get the form data from the request

    my $form = $c->form->parse($c->req->params);

    # Process the form data

    my $user = $c->model('User')->new();

    $user->name($form->{'name'});

    $user->email($form->{'email'});

    $user->insert();

    # Redirect to the list of users

    $c->res->redirect('/users');

}

This code gets the form data from the request using the $c->form->parse() method, and then processes the form data using the $c->model('User')->new() method. Finally, it inserts the new user into the database and redirects to the list of users.

Now you should be able to create a new user by filling out the form on the /users/create page. The new user will be added to the database, and you'll be redirected to the list of users.

Of course, this is just a basic example, and there are many ways you could extend this application. For example, you could add validation to ensure that the user enters valid data, or you could add additional fields to the form. You could also use Catalyst's built-in support for authentication and authorization to restrict access to certain pages.

implementation for authentication and authorization using Perl Catalyst MVC framework:

First, we need to install the required modules:

bash cpanm Catalyst::Authentication cpanm Catalyst::Authorization 

Next, we need to configure the authentication and authorization settings in the config.yml file:

authentications:

type: Credentials

realm: My App

credential_class: Catalyst::Credentials::Password

password_hash: bcrypt

authorizations:

type: RoleBased

roles:

admin

moderator

user

In the above configuration, we defined an authentication type of `Credentials` with a realm of `My App`. We also specified the credential class as `Catalyst::Credentials::Password` and set the password hash algorithm to `bcrypt`.

For authorization, we defined a role-based system with three roles: `admin`, `moderator`, and `user`.

Next, we need to create a login page that will allow users to enter their credentials. We can create a `Login.pm` file in the `views` directory with the following content:

package MyApp::View::Login;

use strict;

use warnings;

use Catalyst qw/Context>;

use Catalyst::Authentication::Credential::Password;

sub render {

    my ($self, $c) = @_;

    # Display a login form

    return $c->render(

        'login.html',

        {

            title => 'Log in',

            username => '',

            password => '',

        }

    );

}

sub login {

    my ($self, $c) = @_;

    # Get the username and password from the form

    my $username = $c->req->parameters->get('username');

    my $password = $c->req->parameters->get('password');

    # Authenticate the user

    my $credentials = Catalyst::Authentication::Credential::Password->new(

        username => $username,

        password => $password,

    );

    $c->authentication->auth($credentials);

    # If authentication successful, redirect to main page

    if ($c->authenticated) {

        return $c->redirect_to('main');

    } else {

        # Display an error message

        return $c->render(

            'login.html',

            {

                title => 'Log in',

                username => $username,

                password => $password,

                error   => 'Invalid username or password',

            }

        );

    }

}

1;

In the above code, we defined a Login view that renders a login form and handles the login process. When the user submits the form, the login method is called, which retrieves the username and password from the form parameters and creates a Catalyst::Authentication::Credential::Password object. The auth method is then called on the authentication object to authenticate the user. If the authentication is successful, the user is redirected to the main page. Otherwise, an error message is displayed.

Next, we need to create a Main.pm file in the views directory to handle the main page:

package MyApp::View::Main;

use strict;

use warnings;

use Catalyst qw/Context>;

sub render {

    my ($self, $c) = @_;

    # Check if the user is logged in

    unless ($c->authenticated) {

        return $c->redirect_to('login');

    }

    # Display the main page

    return $c->render(

        'main.html',

        {

            title => 'Welcome, ' . $c->user->username,

        }

    );

}

1;

In the above code, we defined a Main view that checks if the user is logged in before rendering the main page. If the user is not logged in, the Main view redirects the user to the login page.

we need to create a roles.yml file in the conf directory to define the roles and permissions:

roles:

admin:

    - MyApp::Controller::Admin

  moderator:

    - MyApp::Controller::Moderator

  user:

    - MyApp::Controller::User

permissions:

  admin:

    - MyApp::Action::Index

    - MyApp::Action::Create

    - MyApp::Action::Read

    - MyApp::Action::Update

    - MyApp::Action::Delete

  moderator:

    - MyApp::Action::Index

    - MyApp::Action::Create

    - MyApp::Action::Read

    - MyApp::Action::Update

    - MyApp::Action::Delete

  user:

    - MyApp::Action::Index

    - MyApp::Action::Read

In this example, we define three roles: admin, moderator, and user. Each role has a list of permissions associated with it. The admin role has all the permissions, while the moderator role has fewer permissions than the admin role. The user role has only the index and read permissions.

We can now use these roles and permissions to secure our application. For example, we can use the before filter to check if the current user has the required permissions to access a particular action:

use Catalyst::Action::Before;

sub before {

    my ($self, $c) = @_;

    # Check if the user has the required permissions

    my $required_permissions = [qw(index read)];

    unless ($c->user->has_permissions($required_permissions)) {

        # Redirect the user to an error page or deny access

        return $c->redirect_to('error', 'You do not have permission to access this resource.');

    }

}

In this example, we define a before filter that checks if the current user has the index and read permissions. If the user does not have these permissions, we redirect them to an error page.

We can also use the around filter to enforce permissions on a per-action basis:

use Catalyst::Action::Around;

sub around {

    my ($self, $c) = @_;

    # Check if the user has the required permissions

    my $required_permissions = [qw(update delete)];

    unless ($c->user->has_permissions($required_permissions)) {

        # Redirect the user to an error page or deny access

        return $c->redirect_to('error', 'You do not have permission to update or delete resources.');

    }

    # Call the next action in the chain

    return $next->(@args);

}

In this example, we define an around filter that checks if the current user has the update and delete permissions. If the user does not have these permissions, we redirect them to an error page.

These are just a few examples of how you can use roles and permissions in Catalyst. You can customize the roles and permissions to fit your application's needs, and use them to secure your application's resources.

Define the roles and permissions

Next, we need to define the roles and permissions that we want to use in our application. We can do this by creating a roles.yml file in the conf directory of our application.

Here's an example roles.yml file that defines two roles: admin and user:

admin:

  - MyApp::Action::Index

  - MyApp::Action::Create

  - MyApp::Action::Read

  - MyApp::Action::Update

  - MyApp::Action::Delete

user:

  - MyApp::Action::Index

  - MyApp::Action::Read

In this example, we define two roles: admin and user. The admin role has all the permissions, while the user role has only the index and read permissions.

Create a permission handler

Next, we need to create a permission handler that will check the permissions of the current user when they request a resource. We can do this by creating a PermissionHandler class that inherits from Catalyst::Action::PermissionHandler.

Here's an example PermissionHandler class that checks the permissions of the current user:

package MyApp::PermissionHandler;

use base 'Catalyst::Action::PermissionHandler';

sub _check_permission {

    my ($self, $c, $action, $params) = @_;

    # Get the current user's roles

    my $current_user = $c->user;

    my $roles = $current_user->roles;

    # Check if the user has the required permission

    my $required_permissions = [qw(index read)];

    unless ($roles->contains_any($required_permissions)) {

        # Redirect the user to an error page or deny access

        return $c->redirect_to('error', 'You do not have permission to access this resource.');

    }

    # Return true to indicate that the user has the required permission

    return 1;

}

1;

In this example, we define a _check_permission method that gets the current user's roles and checks if they contain any of the required permissions. If the user does not have the required permissions, we redirect them to an error page. otherwise, we return 1 to indicate that the user has the required permission.

Add the permission handler to the application

Finally, we need to add the permission handler to our application. We can do this by adding the following line to our Config.pm file:

catalyst_app->add_permission_handler(MyApp::PermissionHandler->new);

This line adds the MyApp::PermissionHandler class as a permission handler to our application.

With these steps, we have implemented a simple permission system in our Catalyst application. The system uses roles to define the permissions that a user needs to access a resource, and a permission handler to check the permissions of the current user when they request a resource.

Note that this is just a simple example, and you may need to modify it to fit your application's requirements. Additionally, you may want to consider using a more sophisticated permission system, such as one that uses Access Control Lists (ACLs) or a Role-Based Access Control (RBAC) system.

Labels:

0 Comments:

Post a Comment

Note: only a member of this blog may post a comment.

<< Home