Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Catalyst Redirect Hints?

by pileofrogs (Priest)
on Mar 25, 2009 at 21:17 UTC ( [id://753259]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks.

I'm working on a Catalyst app. I want to make things nicer when people hit the app, discover they're logged out, and then log in. I not only want to redirect to the originally intended page, but I also want to include any parameters in that redirect.

This is primarily to ease testing for me. I'll fill out a form, get an error, apply a fix, restart the fcgi process, and then I'll hit reload, which resends my query. But I'm logged out because I restarted the server. So, I get bounced to my login screen. I then have to log in and re-enter everything in my form.

What I want to do is submit my request, get bounced to the login screen and then after login, have my originally submitted request processed. I don't even want to see the form again.

I assume this means populating $c->response in some way. Should I go through $c->request->params and stick everything on the URL that I redirect to, or is there a better way?

Thanks!
--Pileofrogs

Replies are listed 'Best First'.
Re: Catalyst Redirect Hints?
by Your Mother (Archbishop) on Mar 25, 2009 at 22:36 UTC

    This can be semi-trivial in Cat. There are two ways to do it. The first, easiest, is debatably bad REST style (the content under any restricted URI becomes fluid; it's a login form or the real content) but the second can be tricky and has no "standard" implementation.

    1. Forward to login action under the requested URI until user is authenticated. Once authenticated, the requested URI never changed so it's trivial to redirect to the same resource.
    2. Capture the request info, put it in the session via flash or cache or session, redirect to login, keep the info there via flash, cache, or session and use it to send the user where they tried to start once they authenticate. This is trickier because you probably have to take into account request->referer existing or not and if its base equals that of the app's otherwise you could redirect an authenticated user off-site.

    I recommend #1. Pseudo-code:

    sub what_i_want : Local { $c->detach("login") unless $c->user_exists... roles... etc... do_interesting_restricted_stuff() } sub login : Local { if ( authenticated... ) { my $destination = $c->request->path eq 'login' ? $c->uri_for("/") : $c->uri_for( "/" . $c->request->path +); $c->response->redirect($destination); $c->detach(); } }

    So, the user requests http://myapp/what_i_want but is presented with the login page since they aren't authenticated. The login posts to that same path, "what_i_want," until they are authenticated. Then just redirect to the requested path as long as it wasn't "login" to start with, that would be silly. Send them home -- "/" -- if they requested login to start the login process.

    I know that can be a bit boggling at first but it's actually pretty straightforward once you get the right perspective on it. There is more of this in a few of the docs, sorry, no links right now. Let me (us) know if you get stuck on it.

      If you put that in a auto function you don't even need to call it from the controller action. At my current project I am using this base controller for the protected area.
      package XXXXX::SecureBaseController; use strict; use warnings; use parent 'Catalyst::Controller'; sub auto: Private { my ( $self, $c ) = @_; # ungültiges User-Objekt in der Session unless ( $c->session->{user} ) { # Umleitung zum Login $c->response->redirect('/login/'.$c->request->path); return; } return 1; } 1;


      holli

      When you're up to your ass in alligators, it's difficult to remember that your original purpose was to drain the swamp.

        Nice approach++. I also generally do this stuff in auto() as well but not that way. I may adopt that myself. It's quite direct.

        Update: Oh, but I would change part of it.

        $c->response->redirect('/login/'.$c->request->path);

        Should be-

        $c->response->redirect($c->uri_for('/login', $c->request->path));

        Redirects are supposed to be absolute URIs (per the HTTP spec) and even though most stuff accommodates the relative ones there is at least one real world bug: I've seen them do freaky stuff in mod_perl; internally redispatching to an unrelated part of the app. That was a drag to track down.

Re: Catalyst Redirect Hints?
by shmem (Chancellor) on Mar 25, 2009 at 21:51 UTC

    Store the posted variables on behalf of the browser. Create a unique key which you can later use to reference that posted content (and its origin), and serve the login page including that key as a hidden variable in the login form. If the login succeeds, serve the original form with the saved variables filled in. No redirects involved. Of course you need some code to clean up that non-authenticated posted content, if the login fails (or time runs out).

    I don't know the Catalyst specifics to do that, but that's how I'd do it - i.e. create a non-authenticated session which results in serving the login form.

      The problem with this is that you can't present the original form with the values filled in if the form contains file upload widgets or password fields. Browsers often refuse to fill those out because you can be tricked into uploading files you didn't intend to, /etc/passwd or something.

      But storing all the posted content and then forwarding to the processing page for the original form may work somewhat. Usually when you hit a protected page and you're not logged in, you get forwarded to the login page (via an internal or external redirect). You will have to ensure it's an internal redirect so you still have access to the POST content or don't redirect at all, intercept the request and present the login form at the original URL they requested.

        Well it depends on the design of the app and the data being POSTed, of course. I'd not serve a file upload form nor process it without proper authentication, unless I'd purpose being flooded with SPAM of all sorts.

        But the requirement "allow POSTing first, authenticate later" looks a bit weird to me, I have to confess.

Re: Catalyst Redirect Hints?
by Your Mother (Archbishop) on Mar 26, 2009 at 06:45 UTC

    Oh, say, you know, I pretty much missed the point of your OP. Sorry. Putting the params in the redirect URI should work fine if the length isn't crazy (<= 2K I think works on most browsers). Probably best to take them out of request->body_params if it's a post form. It won't preserve file uploads but everything else should work. Since it's just for testing I don't see any problems with this.

    Oh, actually I'm still being stupid. Check out Catalyst::Plugin::Session::PerUser. I haven't had a chance to try it yet but it's probably just the ticket.

Re: Catalyst Redirect Hints?
by saberworks (Curate) on Mar 25, 2009 at 21:32 UTC
    I think this may be a problem if the forms are being POSTed. As far as I know, you can't do a POST redirect, only a GET. If you're only concerned about GET, the way I've seen it done before is that all the parameters are forwarded along to the login page (usually in a session or in hidden parameters), then forwarded again to the "process" login page, and then that page redirects you back to the form submission with the parameters tacked onto the end of the URL. I don't think this is possible with POST though.

    Update: I should have said, I don't think it's possible with perl. There are a number of hacky solutions out there that I pulled up in a google search. A perl book suggests converting all posted parameters to get parameters and then redirecting as a GET. That will lose any file uploads and will break forms if their processing programs are specifically looking for POST requests. Another option would be to redirect them to the form itself and prefill it so they can continue where they were. This will again lose all file upload fields and passwords because browsers don't fill those in if you set their values in the HTML. I read one other solution that recommended rebuilding the form using javascript (hidden) and then using a client-side submit() method to submit the form.

Re: Catalyst Redirect Hints?
by Gryllida (Acolyte) on Feb 03, 2013 at 00:40 UTC

    > But I'm logged out because I restarted the server.

    Use the catalyst session plugin and it won't happen?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (11)
As of 2024-04-23 21:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found