http://qs321.pair.com?node_id=384881

deep submerge has asked for the wisdom of the Perl Monks concerning the following question:

I post my troubles with great hesitation... Again, I've looked all over for information about logins with CGI::Application and CGI::Application::Session. I've super searched, I've Googled, and I've wiki-ed. None of it seems to make enough sense for me to keep coding.

All I've gathered so far is that many would prefer to seperate authentication and the actual guts of the program into two C::As. But I don't get it? Why? Why do that?

Questions like... Which parts of the program actually need to be run modes? The nouns (results) or the verbs (the actions)? Where does my validation function go? How do I store/work with a session? How do I debug C::A?

I don't know. I'm so confused. I wish someone would just hold my hand and post a very concrete example of a C::A with login. I've read through so many already (its been hours) and none of them make sense. Again, I feel silly.

Thoughts, oh wise ones?

Edit: Forgot to mention the use of C::A::S...

  • Comment on Starting with CGI::Application(::Session) and Logins

Replies are listed 'Best First'.
Re: Starting with CGI::Application and Logins
by Zed_Lopez (Chaplain) on Aug 22, 2004 at 08:04 UTC

      In your example, your starting run mode is the login screen. I thought the login screen was supposed to be determined in prerun? I saw an example somewhere, where the need to validate a user's login was supposed to the login. If it was good, it would go to the normal run mode. If it was bad, it would return $self->desiredrunmode.

      And the wiki doesn't help either. It made some reference to a catch-all validation, that made a seperate C::A necessary. I see that you have everything in one pm...

      See, I still don't understand what's going on, anywhere.

      In your example, your start mode is login... And then your prerun is login... So how does the user get out of the login stage if they already were logged in?

        Good question. I was fiddling with the code at the last minute and I made one of the classic mistakes -- putting a naked 'shift' into a hash parameter. So my login_required function, as written, didn't work, but (subsequent to breaking it) I hadn't tested the case of the user trying an end run around logging in by going to a run mode that required it.

        I've updated the code, and maybe my prerun makes more sense now that it's governed by a function that actually works.

        Updated: I wasn't really addressing all the questions, so I added the following...

        The example with the desired_runmode you mention does something nice that this example doesn't -- if the user's not logged in (perhaps because his or her session expired), it directs them to the login screen, while remembering where they wanted to be, and directing them there after they're logged in. That's functionality that just isn't here -- here, when they log in, they go to main, period. (Of course in this example there's literally nowhere else to go.)

        My prerun returns without action if they're going to a run mode that doesn't require being logged in, e.g. the login and create account run modes and the run modes that process the submission of those forms. Then, having determined they're going to a run mode that does require being logged in, it checks if they're logged in, and returns without action if they are. Finally, having eliminated the above cases, it knows that the user is going to a run mode that requires being logged in, and that the user is not logged in, so it directs the user to the login screen.

        I am a CGI::Application beginner myself, and have no idea why someone would say something actually required splitting the application into multiple C::A's. Can you provide a link to that assertion?

Re: Starting with CGI::Application and Logins
by Your Mother (Archbishop) on Aug 22, 2004 at 07:16 UTC
    PrivateSpace::
                ::Display
                ::DataBase
                ::Session
                ::CGI

    This is not any kind of final word on the matter. Just a suggested outline. See also Code and html separation - always or mostly doable?, and others from the search.

    If you don't separate your business logic from your display logic you get self-involved spaghetti code. It's difficult at first to realize this b/c it seems natural to write it all together but for a big project it's Wrong and will bite you. Imagine if you will that DBI and CGI and Mason were all one module called WebDataDisplay or something. You can see how awful and un-modular it becomes. It's no longer a tool to pick up and use but an application that either fits or doesn't and if it doesn't then all the shoe-horns in Taiwan might not turn the trick.

Re: Starting with CGI::Application(::Session) and Logins
by weierophinney (Pilgrim) on Aug 23, 2004 at 01:15 UTC

    The way I've approached the issue is thusly:

    • Logins happen once per session, usually
    • Logins usually have to do with user authentication, user creation, and user management -- all potential run modes for an application of their own
    • Other applications, built on CGI::App, may require an authenticated user, but don't care how that happens -- only that certain traces indicating a user was authenticated are present
    • The way to track whether or not a user is authenticated is usually done via a session and/or a cookie

    There are a lot of applications out there that look like they're doing everything -- user creation, user authentication, user management, shopping carts, forums, etc., but usually, when you dig deep in the guts of them, you'll discover that they are built modularly, with each module doing one thing, and one over-riding module/application binding it all together.

    CGI::Application can look like that, too, but usually what you'll find is good authors have written a super class of CGI::App that checks for authenticated users, active sessions, etc. -- and that each separate application (user management, shopping cart, forum, wiki, etc.) then uses this as its base. The super class will usually then have some sort of mechanism that redirects to the user management class instance when authentication is necessary. Each application has its own class -- that way, when you go to refactor, debug, or extend it, you know that that class does ONE thing -- and everything to do with that one thing -- and that one thing ONLY. It may have many run modes, or very few run modes, but you know when you look at your shopping cart class, you're not going to be doing anything that affects your forum logic. (You may even find that sometimes if your class gets too big and unwieldy that it's time to refactor it and break it into more distinct applications; but that's another story.)

    So, again, the basic idea is that you have one CGI::App class that handles user authentication and everything to do with user management, and then have the authentication method take care of initializing a session. Then your other applications all inherit from a super class that looks for that session (hence CGI::Application::Session) in order to verify whether or not a run mode is allowed at a given point in time.

Re: Starting with CGI::Application(::Session) and Logins
by Anonymous Monk on Aug 22, 2004 at 16:55 UTC
    Logins should use separate authentication becase including it in any CGI program will typically overcomplicate things. Not to mention the significant potential to leave holes in your authentication methods. Simply put, authentication is best left OUT of your program.

    Authentication is best done by your web server, which will leave no doubts as far as who is allowed to see what by the time they get to your script. Storing sessions is a different topic, although related.