Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Re: first steps with Mojolicious::Lite

by Anonymous Monk
on Jun 15, 2020 at 15:29 UTC ( [id://11118099]=note: print w/replies, xml ) Need Help??


in reply to first steps with Mojolicious::Lite

An idea: use Mojo's under sub { ... } to run the code you need to run in both cases (i.e. check authentication), then provide two short routes get '/get_X' => sub { shift->render(...); }. If the code in under sub {...} returns a truthy value, the get routes get a chance to fire. If it returns undef, Mojo behaves as if they don't exist (so, 404 for unauthenticated users). The code in under can also call shift->render(...) instead of returning undef to send its own response. See Mojolicious::Guides::Routing for a better explanation.

Replies are listed 'Best First'.
Re^2: first steps with Mojolicious::Lite
by Discipulus (Canon) on Jun 15, 2020 at 16:11 UTC
    Thanks Anonymous Monk for the hint,

    I looked at Under and it seems powerful, maybe a bit too much framew-orcish at the moment. Or, if you prefere, too much sugar for my taste. Surely for my ignorance but when I see my $foo = $r->under('/foo')->to('foo#baz'); I cannot see immediately what is passing on.

    But anyway thanks for the hint; something to study.

    But, if I dont misunderstand myself, I have not duplicated code in the actual code: the IP check and the authentication only happens in get_first while in get_second only a cookie is checked, no?

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      But, if I dont misunderstand myself, I have not duplicated code in the actual code: the IP check and the authentication only happens in get_first while in <c>get_second only a cookie is checked, no?

      Well yes, but since http is stateless, what happens if get_second gets called first?

      I'm developing some Mojolicious::Lite apps at the time, and my layout is as follows

      #!/usr/bin/perl use Mojolicious::Lite; use Foo::Blargh; # yadda yadda, other usefull stuff get "/login" => sub { my $c = shift; # $c is the controller object $c->render('login'); # renders templates/login.html.ep }; # this sub checks username and password post "/login" => sub { validate_user(shift); # the sub gets the controller }; get "/logout" => sub { my $c = shift; $c->cookie(MySession => 'none'); # unset cookie $c->redirect_to("/login"); }; # with the following, all following routes require # a logged-in user and a proper cookie under sub { validate_cookie(shift); }; # more routes get "/foo" => sub { my $c = shift; ... $c->render($whatever); }; get "/bar" => sub { my $c = shift; ... $c->render($something_else); }; # all set up, start the application; app->start; ### ## # subs sub validate_cookie { my $c = shift; my $cookie = $c->cookie('MySession'); if (! $cookie) { $c->redirect_to('/login'); return; # important! } else { # more checks to see if cookie is valid ... } 1; } sub validate_user { my $c = shift; my $u = $c->param('user'); my $p = $c->param('pass'); if ( login($u,$p) ) { # set cookie. Multiple cookies can be set by calling # $c->cookie() with other key/value pairs more than 1 time $c->cookie(MySession => generate_cookie() ); $c->redirect_to('/foo'); # whatever is appropriate return; } $c->stash(error => 'wrong user or password'); # gets rendered in / +login $c->render('login'); return; } sub login { # validate user and password: database, ldap, ... # returns 1 on success, nothing on failure } sub generate_cookie { my $n = shift || 42; my @chars = ('A'..'Z','a'..'z',0..9,'+','/' ); # we use the BASE64 + chars join '', map{ $chars[rand @chars] }1..$n; # session ID }

      Works for me ;-)

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        thanks shmem really appreciated,

        > what happens if get_second gets called first?

        I suppose my application will reject the request because the cookie was not set; is my mojo DWIM? But this is not importatnt at the moment.

        I still miss the meaning of this sugar called under and I read about it. I cant capacitate how your example can be similar to others in this thread where syntax like my $foo = $r->under('/foo')->to('foo#baz'); are presented like in the docs.

        How other examples in this thread can use under in a total different way?

        With your comment with the following, all following routes require a logged-in user and a proper cookie you mean that if some route is positioned in the file after an under one, this is executed? Like as it was a pragma no strict usage?

        Sincerily I found this option highly unreadable: or, as you have done, you put a BIG comment stating it clear, or after 100 lines everyone forget the under is in use. I see you can group routes using under and sounds saner... but I miss the sense of the code presented in the example.. ( the route is /admin/dashboard or /dashboard ??)

        Anyway thanks a lot to you and to all others contributors of this thread

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Hi Discipulus,

      I have really looked forward to assisting you in some trivial matter because of the MAJOR enlightenment and joy you add to Perlmonks!!

      You really need to look at under because it is exactly what you want, I'm pretty sure!

      I'll try to provide some code specific to your example, but this is from a small web site (like 200 occasional users)

      my $onlyLoggedIn = $r->under('/admin' => \&loggedIn); $onlyLoggedIn->post('uploadFile')->to('files#insert'); $onlyLoggedIn->delete('files')->to('files#delete'); sub loggedIn { my $c = shift; if ($c->session('login')) { return 1; } $c->render( template => 'login', title => 'website title', status => 401, ); return 0; }; # elsewhere sub login { my $self = shift; my $name = $self->param('user'); my $password = $self->param('password'); my $responseCode = 401; # Pretty sure this hashes the param and checks it against the +hashed database entry if (Something::Model::Users::login($name,$password)) { # $self->signed_cookie(loggedIn => 1); $self->session(expiration => 60*60*10); $self->session(login => $name); $responseCode = 200; $self->app->log->warn("$name logged in."); } else { $self->app->log->warn("Invalid login - '$name'"); } $self->render(data => '',status => $responseCode); }

      So we have all urls /admin/whatever for only authenticated users.

      Something I recently learned

      $self->helper( onlyauth => sub { my ($c,$block) = @_; if ($c->session('login')) { return $block->() if $block; } });

      So I can use this in my templates!! I have an admin bar at the top of every regular page that only logged in users see

      %= onlyauth begin %= include 'adminbar' % end
        Manual shows layout ... A daddy template

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (2)
As of 2024-04-25 06:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found