package Login;
use base 'CGI::Application';
use Login::User;
use DBI;
use CGI::Session;
use warnings;
use strict;
use Taint;
my $cookie_name = 'example';
my $script = 'test.cgi';
my $cookie_expiry = '+2h';
my $dbinfo = { db => "db", user => "db_user", password => "db_password" };
my $dbh = DBI->connect("DBI:mysql:".$dbinfo->{db}, $dbinfo->{user}, $dbinfo->{password}, {RaiseError => 1, PrintError => 0, AutoCommit => 1});
{
my @no_login_required = (qw(create process_login process_create login logout AUTOLOAD)); # run modes that won't redirect you to login for not being logged in
my %no_login_required_hash;
@no_login_required_hash{@no_login_required} = undef;
sub login_required { return !exists $no_login_required_hash{+shift} }
}
sub cgiapp_init {
my $self = shift;
my $query = $self->query;
# get the current session id from the cookie
my $sid = $query->cookie($cookie_name) || undef;
# session setup
my $session = CGI::Session->new('driver:MySQL', $sid, {Handle=>$dbh });
# assign the session object to a param
$self->param(session => $session);
# send a cookie if needed
if ( !defined $sid or $sid ne $session->id ) {
my $cookie = $query->cookie(
-name => $cookie_name,
-value => $session->id,
-expires => $cookie_expiry,
);
$self->header_props( -cookie => $cookie );
}
}
sub cgiapp_get_query {
my $self = shift;
require CGI::Safe;
my $q = CGI::Safe->new();
return $q;
}
sub setup {
my $self = shift;
$self->run_modes(
main => 'main',
login => 'login',
process_login => 'process_login',
process_create => 'process_create',
create => 'create',
logout => 'logout',
AUTOLOAD => 'autoload_error',
);
$self->start_mode('login');
$self->mode_param('rm');
}
sub autoload_error {
my $self = shift;
my $q = $self->query();
my $output = "";
$output .= $q->start_html(-title => "Invalid");
$output .= $q->h1("invalid runmode " . $self->get_current_runmode);
$output .= $q->end_html();
return $output
}
sub main {
my $self = shift;
my $session = $self->param('session');
my $q = $self->query();
my $output = "";
$output .= $q->start_html(-title => "Main");
$output .= $q->h1("Do something useful here.");
$output .= $q->p("You are logged in as " . $session->param('login'));
$output .= $q->p($q->a({href => "$script?rm=logout"}, "Logout"));
$output .= $q->end_html();
return $output
}
sub login {
my $self = shift;
my $q = $self->query();
my $output = "";
$output .= $q->start_html(-title => "Login");
$output .= $q->startform();
if ($self->param('message')) {
$output .= $q->h3($self->param('message'));
}
$output .= $q->h1("Please login.");
$output .= "Login: " . $q->textfield(-name => 'login') . "
";
$q->param('password', '');
$output .= "Password: " . $q->password_field(-name => 'password', -default => '') . "
";
$output .= $q->submit(-name => 'Submit', -value => 'submit');
$q->param('rm', 'process_login'); # make sure CGI.pm doesn't clobber rm submitted below with value from URL
$output .= $q->hidden(-name => 'rm', -value => 'process_login', -default => '');
$output .= $q->endform();
$output .= $q->p($q->a({-href=>"$script?rm=create"}, "Create new account"));
$output .= $q->end_html();
return $output
}
sub process_login {
my $self = shift;
my $q = $self->query();
my $output = "";
$output .= $q->start_html(-title => "processing login");
my $user = Login::User->retrieve(login => $q->param('login'));
if (!defined $user) {
$self->param('message', 'Specified user does not exist.');
return $self->login;
} else { # user is defined
my $password = $user->get('password');
if ($q->param('password') ne $password) {
$self->param('message', 'Password incorrect');
return $self->login;
} else { # successful login!
my $session = $self->param('session');
$session->param('logged_in', 1);
$session->param('login', $q->param('login'));
$session->expires('logged_in', '+2h');
return $self->main;
}
}
$output .= $q->end_html();
return $output
}
sub create {
my $self = shift;
my $q = $self->query();
my $output = "";
$output .= $q->start_html(-title => "Create Account");
$output .= $q->startform();
if ($self->param('message')) {
$output .= $q->h3($self->param('message'));
}
$output .= $q->h1("Please enter the information for your new account.");
$output .= "Login: " . $q->textfield(-name => 'login', -default => defined $self->param('login') ? $self->param('login') : '') . "
";
$q->param('password','');
$q->param('password2','');
$output .= "Password: " . $q->password_field(-name => 'password', -default => '') . "
";
$output .= "Verify Password: " . $q->password_field(-name => 'password2', -default => '') . "
";
$output .= $q->submit(-name => 'Submit', -value => 'submit');
$q->param('rm', 'process_create'); # make sure CGI.pm doesn't clobber rm submitted below with value from URL
$output .= $q->hidden(-name => 'rm', -value => 'process_create');
$output .= $q->endform();
$output .= $q->end_html();
return $output
}
sub process_create {
my $self = shift;
my $q = $self->query();
my $user = Login::User->retrieve(login => $q->param('login'));
if (defined $user) {
$self->param('message', 'Login already exists. Please choose another.');
return $self->create;
}
if ($q->param('password') ne $q->param('password2')) {
$self->param('message', "Passwords don't match. Please try again.");
$self->param('login', $q->param('login'));
return $self->create;
}
$user = Login::User->create({login => $q->param('login'), password => $q->param('password')});
my $session = $self->param('session');
$session->param('login', $q->param('login'));
$session->param('logged_in', 1);
$session->expires('logged_in', '+2h');
return $self->main;
}
sub logout {
my $self = shift;
my $q = $self->query();
my $sid = $q->cookie($cookie_name);
my $session = $self->param('session');
$session->clear('logged_in');
$self->param('message', 'Logged out.');
return $self->login;
}
sub cgiapp_prerun {
my $self = shift;
return unless login_required($self->get_current_runmode);
my $session = $self->param('session');
$self->prerun_mode('login') unless defined $session and $session->param('logged_in'); # Redirect to login, if necessary
}
1;
####
package Login::DBI;
use base "Class::DBI::mysql";
__PACKAGE__->connection( "dbi:mysql:db", "db_user", "db_password" );
1;
##
##
package Login::User;
use base 'Login::DBI';
use strict;
Login::User->table( "user" );
Login::User->columns(All => qw(uid login password));
1;
##
##
#!/usr/bin/perl -w
use Login;
my $app = Login->new();
$app->run();
##
##
CREATE TABLE user (
uid int(10) unsigned NOT NULL auto_increment,
login char(32) default NULL,
password char(16) default NULL,
PRIMARY KEY (uid)
) TYPE=MyISAM;