Hi Monks
I'm having a bit of trouble getting the hang of CGI::Session and was hoping for some incite.

I'm trying to do authentication and session management, i.e. user authenticates with the usual user/pass and then session info is kept so that say you can say 'hello $user' on other pages.

Here is a bit of code hacked from the Members Area example in the cookbook.

#!/usr/bin/perl use strict; use warnings; use DBI; use CGI qw/:standard/; use CGI::Session; use Crypt::PasswdMD5; #Initiate the connection to the database my $dbh = DBI->connect("DBI:mysql:database=DATABASE;host=localhost", " +USER","PASS",{'RaiseError' => 1}); #Create the session #my $session = new CGI::Session("DBI:MySQL", undef, {Handle=>$dbh}); my $session = new CGI::Session(undef, undef, {Directory=>'/tmp'}); #create a CGI instance my $cgi = new CGI; #create a cookie with the session id my $cookie = $cgi->cookie(CGISESSID => $session->id); #$session->header(); sub init { my ($session, $cgi) = @_; if ( $session->param("~logged-in") ) { return 1; } my $trials = $session->param("~login-trials") || 0; my $name = $cgi->param('user') or return $session->param("~login-t +rials", ++$trials);; my $pass = $cgi->param('pass') or return $session->param("~login-t +rials", ++$trials);; if ( my $profile = _load_profile($name, $pass) ) { $session->param("~profile", $profile); $session->param("~logged-in", 1); $session->param("~login-trials",0); return 1; } return $session->param("~login-trials", ++$trials); } sub _load_profile { my ($user, $pass) = @_; local $/ = "\n"; my $query = "SELECT pass,email FROM users WHERE user = '$user'"; my $sth = $dbh->prepare($query); $sth->execute; my $dbpass; my $email; while ( my $ref = $sth->fetchrow_hashref() ) { $dbpass = $ref->{pass}; $email = $ref->{email}; } my @bits = split '\$', $dbpass; my $crypt = unix_md5_crypt($pass, $bits[2]); if ($crypt eq $dbpass) { my $mask = "x"; return {username=>$user, password=>$mask, email=>$email}; } return undef; } sub login_page { print "<br><b>Wrong information</b>\n"; open FILE, "<../login.html" or die "Could not open login file: $!\ +n"; while (<FILE>) { print $_; } close (FILE); } print header, start_html("Logging In..."); my $trials = init($session, $cgi); print "<br>trials = $trials\n"; if ( $session->param("~login-trials") >= 3 ) { print error("You failed 3 times in a row." . "Your session is blocked. Please contact us with" . "the details of your action"); exit(0); } unless ( $session->param("~logged-in") ) { print login_page($cgi, $session); exit(0); } my $profile = $session->param("~profile"); print "<br>Hello $profile->{username} ($profile->{email})"; print "<br><a href=\"home.cgi\">home</a>\n"; print end_html;


The code basically works... I changed the example so it uses a mysql database to authenticate with and that works. So you can use and valid user/pass and it works and if you use and invalid user/pass it doesn't let you in.

One thing doesn't work and one thing I'm not sure how you're supposed to do it.

The bit that doesn't work - The session counter doesn't increment and hence if you fail 3 times you don't get the fail screen. Looking at the /tmp when it keeps the session info it seems that for each refresh it creates a new session and doesn't use the existing one?? Why is this??

The bit I'm not sure about - I want to recall the session from another script, i.e. they click on a link and the next page knows who you are. When you click on the link the browswer would send back the cookie with the session id.
This is the bit I'm not sure about...
Do you basically capture the cookie and then create a new CGI::Session instance with that info so it know which file to look up in /tmp to see if you're logged in... or is it supposed to do all of that automatically?
UPDATE: This bit I've worked out, in the first bit of source I created the cookie, but I never printed it out so that it made it to the client.

Here is where i was heading, but it doesn't work...

#!/usr/bin/perl use strict; use warnings; use CGI qw/:standard/; use CGI::Cookie; use CGI::Session; my %cookies = fetch CGI::Cookie; print header, start_html; print "<br> Booo\n"; print "<br>Cookies:\n"; my $session_vars; foreach my $key (keys %cookies) { $session_vars = $cookies{$key} if ( $key eq 'CGISESSID' ); } my @vars = split ';', $session_vars; my $session_id; foreach my $v ( @vars ) { if ( $v =~ /CGISESSID/ ) { my @bits = split '=', $v; $session_id = $bits[1]; } } print "<br>sess : $session_id\n"; my $session = new CGI::Session(undef, $session_id, {Directory=>'/tmp'} +); my $profile = $session->param("~profile"); print "<br> Hello: $profile->{username}\n"; print end_html;


Update: The second script gets completely gutted now, instead of capturing the cookies youself, you just create a cgi instance and pass it as the second argument in the new CGI::Session initialization and it goes and finds the olds session itself if it exists.

Update2: I have it all working now, the main problem was that I was creating a new session everytime I refreshed the page (or failed a login) which created a new session ID and hence never made the counter more than 1. Below is a snippet that shows what to do...i.e. include the $cgi object in the session call. It uses the CGI to object to see if it has an associated session and if not it makes one.
#Initiate the connection to the database my $dbh = DBI->connect("DBI:mysql:database=DATABASE;host=localhost", " +USER","PASS",{'RaiseError' => 1}); #create a CGI instance my $cgi = new CGI; #Create the session #my $session = new CGI::Session("DBI:MySQL", undef, {Handle=>$dbh}); my $session = new CGI::Session(undef, $cgi, {Directory=>'/tmp'});

Can anyone offer any insight into why the counter does not work for logins??

Regards Paul

READMORE tags added by Arunbear; also changed title from 'CGI::Session'


In reply to Using CGI::Session for authentication by thekestrel

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.