Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Structuring multiple CGI::Application modules

by Anonymous Monk
on Jun 25, 2004 at 20:41 UTC ( [id://369746]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Having nearly finished my first C::A module (it performs authentication), I'm not sure what the best way is to chain to the next C::A module. I want multiple/separate C::A modules to be able to reuse the authentication module. I haven't been able to find many examples of this type and would appreciate suggestions from other C::A users. My current thought is to create the initial script to look like the following untested code:
#!/usr/local/bin/perl use MyAuth; ## has strict, warnings, etc. my $webapp = MyAuth->new( PARAMS => { 'Next_CGI' => "some_url_without_query_string" } ); $webapp->run();
Then teardown() within MyAuth.pm would look like the following:
sub teardown() my $self = shift; my $output = ''; ## probably best to store the following in a file my %Allowed_Scripts = ( 'https://site/pathto/ca.script1.cgi' => 1, 'https://site/pathto/ca.script2.cgi' => 1, ); ## usual teardown stuff my $url = $self->param('Next_CGI'); if ( exists($Allowed_Scripts{$url}) ) { if (authorized) { my $query_string = "?whatever"; $self->header_type('redirect'); $self->header_props( -url => "$url$query_string" ); } else { ## use template for unauthorized user message } } else { ## use template for unauthorized script message } return $output; }
Is this a reasonable way to handle an application using multiple CAs? Will it cause memory problems (bloat)? Thanks.

Replies are listed 'Best First'.
Re: Structuring multiple CGI::Application modules
by valdez (Monsignor) on Jun 25, 2004 at 21:49 UTC

    When I need to share authorization code between different C::A applications, I put the necessary code in the cgiapp_prerun() method of a base module; then every application use that module and inherits everything needed, including some common run modes (i.e. login, login_failed, etc). BTW, this is also the suggested solution in CGI::Application documentation.
    The following is a stripped down example from my code:

    package MyApp::Base; use base 'CGI::Application'; sub cgiapp_init { my $self = shift; # init your application: session, database, whatever is needed ... # set the name of the run mode CGI param $self->mode_param('rm'); # shared run modes $self->run_modes('login' => 'login', 'AUTOLOAD' => 'autoload_exception'); return; } ... sub session { return shift->param('SESSION'); } ... sub cgiapp_prerun { my $self = shift; my $runmode = shift; my $user = $self->session->param('user'); unless ($user) { $self->prerun_mode( 'login' ); } }
    Then in your application you only need to say:
    package MyApp::Application1; use base 'MyApp::Base'; ...
    and your application will be accessible only to authorized users.

    HTH, Valerio

Re: Structuring multiple CGI::Application modules
by MrCromeDome (Deacon) on Jun 25, 2004 at 20:55 UTC

    I haven't been using C::A for too terribly long, but so far, it's been a blessing to my web development efforts ;) Your approach to this is not too dissimilar to my own:

    My applications have a lot in common, from configuration files to session parameters to application parameters. Typically, when one of my apps needs to handle a login, they simply redirect to my user module as follows:

    # Are we logged in? If not, redirect someplace sane! unless(user_is_logged_in()) { $self->param("session")->param("login_redirect", $request->url + . "?mode=modify"); # Redirect! $self->header_type("redirect"); $self->header_props(-url => "/cgi-bin/users.cgi?rm=login"); return "Please wait. . ."; }
    Notice the login_redirect param. Login uses this to decide where to send the user upon a successful login.

    My login handling code then looks like this:

    # Check for username and password my $username = untaint_string($request->param("username")) || ""; my $password = untaint_string($request->param("password")) || ""; # Perform the login? my $page; if($username ne "") { # Log them in! my $check_user = user_login($username, $password); # Check login status if($username eq $check_user) { # Set session parameters $self->param("session")->param("is_logged_in", "Y"); # Where do we redirect upon success? my $redirect = $self->param("session")->param("login_redir +ect"); $redirect = $config{URL_BASE} unless($redirect ne ""); # Redirect! $self->header_type("redirect"); $self->header_props(-url => $redirect); return "Please wait. . ."; } elsif($username eq "INACTIVE") { $self->param("error", "This account is currently inactive. +"); $page = $self->login(); } else { $self->param("error", "Invalid user/password combination. Please enter a ne +w username and password."); $page = $self->login(); } } else { $self->param("error", "Invalid user/password combination. Ple +ase enter a new username and password."); $page = $self->login(); } return $page;
    Some of these functions are from my own application code, but you should get the gist of what is going on.

    Sorry that I am unable to answer your question with regards to bloat. I'm not the best at profiling an application :(

    Hope this helps you somewhat and answers your questions. Feel free to bombard me with your questions.

    Good luck!
    MrCromeDome

Re: Structuring multiple CGI::Application modules
by Arunbear (Prior) on Jun 25, 2004 at 21:21 UTC
    The cgiapp_prerun() method is the natural place to do authentication (teardown is for cleanup e.g. closing database connections).
    The following is from CGI::Application's documentation (see prerun_mode()):
    # In WebApp.pm: package WebApp; use base 'CGI::Application'; sub cgiapp_prerun { my $self = shift; # Get the web user name, if any my $q = $self->query(); my $user = $q->remote_user(); # Redirect to login, if necessary unless ($user) { $self->prerun_mode('login'); } }
    Once you've done something like the above in your MyAuth module, your other modules can subclass MyAuth to reuse the authentication code.
    Some useful nodes: Re: Re: Re: Why CGI::Application?, Re: Breaking up Large Modules..

      Your example is wrong: if you are going to use remote_user information from CGI.pm, then you will never reach that prerun mode without a valid user and the code unless ($user) ... is useless.

      Ciao, Valerio

Re: Structuring multiple CGI::Application modules
by dragonchild (Archbishop) on Jun 28, 2004 at 12:18 UTC
    Re: Why CGI::Application? has my thoughts on the matter.

    Update: Fixed broken link.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

    I shouldn't have to say this, but any code, unless otherwise stated, is untested

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://369746]
Approved by Paladin
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (3)
As of 2025-06-14 23:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.