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;