Here's an implementation of a login system with Mojolicious::Lite and Mojo::SQLite. It may seem fairly long, but some of that code is because I added password encryption using PBKDF2::Tiny and Crypt::Random::Source (Update: and of course because it's entirely self-contained, it includes all the templates etc.). The security could even be expanded, such as adding brute force attack prevention (often done via a delay on unsuccessful attempts), or even hashing the password on the client side. Download the following code as e.g. mojo_login_example.pl, install the aforementioned modules, and then run the command: morbo --listen=http://127.0.0.1:3000 --listen=https://127.0.0.1:4430 mojo_login_example.pl

#!/usr/bin/env perl use 5.028; use Mojolicious::Lite -signatures; use Mojo::SQLite; use PBKDF2::Tiny qw/derive_hex verify_hex/; use Crypt::Random::Source qw/get_strong/; #app->secrets(['A Login Example - TODO: set this string!']); app->sessions->secure(1); # disable template cache in development mode (e.g. under morbo): app->renderer->cache->max_keys(0) if app->mode eq 'development'; helper sql => sub { state $db = Mojo::SQLite->new('sqlite:/tmp/test.db +') }; # Database setup: app->sql->migrations->from_string(<<'END_MIGRATIONS')->migrate; -- 1 up CREATE TABLE Users ( Username TEXT, Salt TEXT, Password TEXT ); -- 1 down DROP TABLE IF EXISTS Users; END_MIGRATIONS # for testing, insert a sample user if the DB is empty: if ( not app->sql->db->query('SELECT COUNT(*) FROM Users')->arrays->[0 +][0] ) { my $salt = unpack 'H*', get_strong(64); app->sql->db->insert('Users', { Username => 'Foo', Salt => $salt, Password => derive_hex('SHA-512', 'Bar', $salt, 5000) } ); } helper logged_in => sub ($c) { length( $c->session('username') ) ? $c->session : undef }; any '/' => sub ($c) { $c->render('index') } => 'index'; group { # everything in this group requires HTTPS b/c of this "under": under sub ($c) { return 1 if $c->req->is_secure; $c->redirect_to( $c->url_for->to_abs->scheme('https')->port(44 +30) ); return undef; }; get '/login' => sub ($c) { $c->render('login') } => 'login'; post '/login' => sub ($c) { # form handler return $c->render(text => 'Bad CSRF token!', status => 403) if $c->validation->csrf_protect->has_error('csrf_token'); # WARNING: This does not (yet) protect against brute-force att +acks! eval { my $u = $c->sql->db->select( 'Users', ['Salt','Password'], { Username => $c->param('username') } )->hashes; die "Username not found" unless @$u==1; utf8::encode( my $salt = $u->[0]{Salt} ); utf8::encode( my $pass = $c->param('password') ); die "Incorrect password" unless verify_hex( $u->[0]{Password}, 'SHA-512', $pass, $salt, 5000); $c->session( username => $c->param('username') ); $c->redirect_to('secure'); ;1} or do { $c->flash(login_error => 'Wrong username or password'); $c->redirect_to('login'); }; } => 'login'; any '/logout' => sub ($c) { delete $c->session->{username}; $c->redirect_to('index'); } => 'logout'; group { # everything in this group requires login under sub ($c) { return 1 if $c->logged_in; $c->redirect_to('login'); return undef; }; any '/secure' => sub ($c) { $c->render('secure') } => 'secure' +; }; }; app->start; __DATA__ @@ layouts/main.html.ep <!DOCTYPE html> <html> <head><title><%= title %></title></head> <body> <nav style="margin-bottom:1em;"><small> [ <%= link_to Main => 'index' %> | <%= link_to Secure => 'secure' %> ] % if ( my $s = logged_in ) { [ Logged in as <%= $s->{username} %> | <%= link_to Logout => 'logo +ut' %> ] % } else { [ <%= link_to Login => 'login' %> ] % } </small></nav> <main> <%= content %> </main> </body> </html> @@ index.html.ep % layout 'main', title => 'Hello, World!'; <div>Hello, World!</div> @@ login.html.ep % layout 'main', title => 'Login'; % if ( flash 'login_error' ) { <div style="margin-bottom:1em;"><strong><%= flash 'login_error' %> +</strong></div> % } <div> %= form_for login => ( method => 'post' ) => begin %= csrf_field %= label_for username => 'Username' %= text_field username => ( placeholder=>"Username", required=>'requir +ed' ) %= label_for password => 'Password' %= password_field password => ( placeholder=>"Password", required=>'re +quired' ) %= submit_button 'Login' %= end </div> @@ secure.html.ep % layout 'main', title => 'Top Secret'; <div>You've accessed the top secret area!</div>

In reply to Re: 302 Found Location Message by haukex
in thread 302 Found Location Message by Walter_T

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.