perl dancer tips


perl cpan dancer

Dancer2

  1. Return to previous page after login (return_url)
    • cpanm install Dancer2::Plugin::Auth::Tiny
    • In config.yml plugin can be configured for the logged_in_key (optional). Indentation is very important. Set logged_in_key value (logged_in) as true in POST ‘/login’ route if username and password matches.
      # for Dancer2::Plugin::Auth::Tiny
        Auth::Tiny:
          logged_in_key: logged_in
      
    • In the lib/project.pm
      # login
      get '/login' => sub {
        # put 'return_url' in a hidden form field  
        #print "================>Thsi is the return url" . params->{'return_url'} . "\n";
        template 'login.tt' => { 
        return_url => params->{'return_url'},
        };
        }; 
      post '/login' => sub {
        my $err;
        if ( request->method() eq "POST" ) {
               # process form input
               if ( params->{'username'} ne setting('username') ) {
                       $err = "Invalid username";
               }
               elsif ( params->{'password'} ne setting('password') ) {
                       $err = "Invalid password";
               }
               else {
                       session 'logged_in' => true;
                       set_flash('You are logged in.');
                       #print "================>Thsi is the return url" . params->{'return_url'} . "\n";
                       return redirect params->{return_url} || '/'; # return to previous page prior to login
                       #return redirect '/';
               }
       } 
       # display login form
       template 'login.tt', {
               'err' => $err,
       };
       };
      
    • In views/login.tt (The “return_url” parameter is needed)
      [% INCLUDE header.tt %]
      <ul class=entries>
      <h2>Login</h2>
      [% IF err %]<p class=error><strong>Error:</strong> [% err %][% END %]
      <form action="[% login_url %]" method=post>
      <dl>
      <dt>Username: <input type=text name=username><br><br>
      <dt>Password: <input type=password name=password><br><br>
      <!--<dt>Return: is [% return_url %]-->
      <input type=hidden name=return_url value=[% return_url %]><br><br><!-- return to pre login page -->
      <dd><input type=submit value=Login>
      </dl>
      </form>
      </ul>
      
    • protected route requiring login. In lib/project.pm (The “needs login” is needed)
      get '/private' => needs login => sub { your code here };
      
  2. encrypted password stored in config.yml
    • cpanm Dancer2::Plugin::Auth::Extensible
    • In config.yml plugin can be configured. Indentation is important.
      plugins:
          Auth::Extensible:
              realms:
                  config:
                      provider: Config
                      users:
                          - user: dave
                            pass: supersecret
                            roles:
                              - Developer
                              - Manager
                              - BeerDrinker
                          - user: bob
                            pass: '{SSHA512}2QOSf9rnEYz8gAJBBFdAK/xEwrYILmRUraJU0WaTsMvMywfnJO5aM38EDSDPZhusjof1PDtcpWbn6oCaX+WLh8vNXeU='
                            roles:
                              - Tester
      
    • Generate the salted hash and paste the output in the pass: above
      dancer2-generate-crypted-password
      
    • In the lib/myapp.pm add the login code
      use Dancer2;
      use Dancer2::Plugin::Auth::Extensible;
      get '/' => require_login  sub {
      template 'index' => { 'title' => 'userauth' };
      };
      
  3. plain text password in mysql db
    • cpanm Dancer2::Plugin::Database
      cpanm Dancer2::Plugin::Auth::Extensible
      
    • In config.yml plugin can be configured. Indentation is important.
      plugins:
        Database:
          connections:
            foo:
              driver: 'mysql'
              database: 'userauth'
              host: 'localhost'
              port: 3306
              username: 'root'
              password: 'secret'
              connection_check_threshold: 10
              dbi_params:
                RaiseError: 1
                AutoCommit: 1
              on_connect_do: ["SET NAMES 'utf8'", "SET CHARACTER SET 'utf8'" ]
              log_queries: 1
              #handle_class: 'My::Super::Sexy::Database::Handle'
      
        Auth::Extensible:
          realms:
            users:
              provider: 'Database'
              db_connection_name: 'foo'
              disable_roles: 1
              users_table: 'active_users'
              roles_table: 'roles'
              user_roles_table: 'user_roles'
              users_id_column: 'id'
              users_username_column: 'username'
              users_password_column: 'password'
              roles_id_column: 'id'
              roles_role_column: 'role'
              user_roles_user_id_column: 'user_id'
              user_roles_role_id_column: 'roles_id'
      
    • Create mysql schema
      CREATE TABLE users (id INTEGER PRIMARY KEY AUTO_INCREMENT,username VARCHAR(32) NOT NULL UNIQUE,password VARCHAR(40) NOT NULL,disabled TIMESTAMP NULL );
      CREATE TABLE roles (id INTEGER AUTO_INCREMENT PRIMARY KEY,role VARCHAR(32) NOT NULL);
      CREATE TABLE user_roles (user_id  INTEGER  NOT NULL,role_id  INTEGER  NOT NULL,UNIQUE KEY user_role (user_id, role_id));
      CREATE VIEW active_users (id, username, password) AS SELECT id, username, password FROM users WHERE disabled IS NULL;
      INSERT INTO users ( username, password, disabled ) VALUES  ( 'Alice', 'test', null), ( 'Bob', 'test', '2017-10-01 10:10:10');
      
    • In the lib/myapp.pm add the login code
      use Dancer2;
      use Dancer2::Plugin::Database;
      use Dancer2::Plugin::Auth::Extensible;
      
      get '/' => require_login  sub {
      template 'index' => { 'title' => 'userauth' };
      };
      
  4. Encrypt password in mysql db
    • Install below modules
      cpanm Dancer2;
      cpanm Dancer2::Plugin::Passphrase; #for crypt salt hash password
      cpanm Data::Dumper; #for debugging
      cpanm Dancer2::Plugin::Database;  #for db connections.
      cpanm Dancer2::Plugin::Auth::Tiny;  #for "needs login" in protected routes
      
    • In config.yml plugin can be configured for the logged_in_key (optional). Indentation is very important. Set logged_in_key value (logged_in) as true in POST ‘/login’ route if username and password matches.
      plugins:
        Database:
          connections:
            foo:
              driver: 'mysql'
              database: 'userauth'
              host: 'localhost'
              port: 3306
              username: 'root'
              password: 'secret'
              connection_check_threshold: 10
              dbi_params:
                RaiseError: 1
                AutoCommit: 1
              on_connect_do: ["SET NAMES 'utf8'", "SET CHARACTER SET 'utf8'" ]
              log_queries: 1
              #handle_class: 'My::Super::Sexy::Database::Handle'
      
        Auth::Tiny:
              logged_in_key: 'logged_in'
      
    • Create mysql schema
      CREATE TABLE users (id INTEGER PRIMARY KEY AUTO_INCREMENT,username VARCHAR(32) NOT NULL UNIQUE,password VARCHAR(40) NOT NULL,disabled TIMESTAMP NULL );
      CREATE TABLE roles (id INTEGER AUTO_INCREMENT PRIMARY KEY,role VARCHAR(32) NOT NULL);
      CREATE TABLE user_roles (user_id  INTEGER  NOT NULL,role_id  INTEGER  NOT NULL,UNIQUE KEY user_role (user_id, role_id));
      CREATE VIEW active_users (id, username, password) AS SELECT id, username, password FROM users WHERE disabled IS NULL;
      INSERT INTO users ( username, password, disabled ) VALUES  ( 'Alice', 'test', null), ( 'Bob', 'test', '2017-10-01 10:10:10');
      
    • The lib/userauth.pm file
      package userauth;
      use Dancer2;
      use Dancer2::Plugin::Passphrase; #for crypt salt hash password
      
      use Data::Dumper;
      use Dancer2::Plugin::Database;  #for db connections.
      #use Dancer2::Plugin::Auth::Extensible;  #for automatic /login route etc
      use Dancer2::Plugin::Auth::Tiny;  #for "needs login" in protected routes
      
      sub set_flash {
          my $message = shift;
      
          session flash => $message;
      }
      
      hook before_template => sub {
             my $tokens = shift;
      
             $tokens->{'css_url'} = request->base . 'css/style.css';
             $tokens->{'login_url'} = uri_for('/login');
             $tokens->{'logout_url'} = uri_for('/logout');
      };
      
      # mysql db settings.
      sub connect_db {
        my $db = DBI->connect('DBI:mysql:userauth', 'root', 'secret') or
           die $DBI::errstr;
      
        return $db;
      }
      
      # subroutine for fetching password from db.
      sub fetch_password_from_db {
          my ($username,$password) = @_;
          my $db = connect_db();
          my $sqltransaction = 'select username,password from users where username=(?)';
          my $sthtransaction = $db->prepare($sqltransaction) or die $db->errstr;
          $sthtransaction->execute($username) or die $sthtransaction->errstr;
      
          my $sqlresultuserrow = $sthtransaction->fetchrow_hashref;
      
          return $sqlresultuserrow; 
      };
      
      # login
      get '/login' => sub {
             # put 'return_url' in a hidden form field  
             template 'login.tt' => { 
             return_url => params->{'return_url'},
             };
      };    
      
      post '/login' => sub {
            my $err;
            #username and password provided by login form
            my $username = param('username');
            my $password = param('password');
            #fetch values from db
            my $saved_userpass = fetch_password_from_db($username,$password);
            my $stored_username_string = $saved_userpass->{username};
            my $stored_rfc_2307_string = $saved_userpass->{password};
      
            if ( params->{'username'} ne ( $stored_username_string ) ) {
      
            #username is ok.
            $err = "Invalid username";
      
            }
      
            elsif ( passphrase( param('password') )->matches( $stored_rfc_2307_string ) ) {
            # Passphrase matches!
            print "\nPassphrase matches ========================>>>>>>\n";
      
            session 'logged_in' => true;
            set_flash('You are logged in.');
      
            redirect params->{'return_url'} || '/'; # return to previous page prior to login
      
          }
            else {
              print "\nPassphrase does not match ========================>>>>>>\n";
              $err = "Invalid password";
          }
      };
      
      #user registeration form.
      get '/register' => sub {
      
          template 'register' => { 
          'title' => 'registeration form',
          register_user_url => uri_for('/register'),
          };
          };
      
      #route for inserting in db.
      post '/register' => sub {
      
          my $username = param('username');
          my $password = passphrase(param('password'))->generate(
          {
              algorithm => 'Bcrypt',
              Bcrypt   => {
                  cost => 04,
              }
          }
          );
      
          # $password is now a hashed password object
          save_user_in_db( $username, $password->rfc2307 );
      
          #template registered => { success => 1 };
      };
      
      # save user and password (crypt salted hash) in db.
      sub save_user_in_db {
          my ($username, $password) = @_;
          my $db = connect_db();
          my $sqltransaction = 'insert into users(username, password) values(?, ?)';
          my $sthtransaction = $db->prepare($sqltransaction) or die $db->errstr;
          $sthtransaction->execute($username, $password) or die $sthtransaction->errstr;
      };
      
      get '/private' => needs login => sub {
          template 'index' => { 'title' => 'userauth' };
      };
      
      get '/logout' => sub {
             context->destroy_session;
             set_flash('You are logged out.');
             redirect '/';
      };
      
      get '/generate_new_password' => sub {
          return passphrase->generate_random;
      };
      
      true;
      
    • views/register.tt
      <h2>Register</h2>
      [% IF err %]<p class=error><strong>Error:</strong> [% err %][% END %]
      <form action="[% register_user_url %]" method=post>
      <dl>
      <dt>Username:
      <dd><input type=text name=username>
      <dt>Password:
      <dd><input type=password name=password>
      <dd><input type=submit value=Login>
      </dl>
      </form>
      
    • views/login.tt
      [% IF vars.login_failed %]
      <div class="alert alert-danger">
      <strong>Login Failed</strong> Try again
      <button type="button" class="close" data-dismiss="alert" aria-label="Close">
      <span aria-hidden="true">&times;</span>
      </button>
      </div>
      [% END %]
      
      <form method = "post" lpformnum="1" class="form-signin">
      <h2 class="form-signin-heading">Please sign in</h2>
      <label for="username" class="sr-only">Username</label>
      <input type="text" name="username" id="username" class="form-control" placeholder="User name" required autofocus>
      <label for="password" class="sr-only">Password</label>
      <input type="password" name="password" id="password" class="form-control" placeholder="Password" required>
      <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
      <br>
      <input type="hidden" name="return_url" value="[% return_url %]">
      </form>
      
  5. fetchrow_array in lib/xxxxxx.pm
    • Select from mysqldb and get the resulting data as an array
      # start festival data structure
      my $sql4='SELECT feast,url,description FROM `festivals` WHERE `date` = CURDATE()';
      my $sth4 = $db->prepare($sql4) or die $db->errstr;
      $sth4->execute or die $sth4->errstr;
      my $feast;
      my $url;
      my $description;
      ($feast, $url,$description) = $sth4->fetchrow_array();
      $sth4->finish;
      my ($feastnameRef,$urlRef,$descriptionRef) = ($feast,$url,$description);
      # end festival data structure
      
      
      template 'query5.tt', {
      'countryname' => $countrynameRef,
      'statename' => $statenameRef,
      'cityname' => $citynameRef,
      'churchid' => $churchidRef,
      'feastname' => $feastnameRef,
      'feastdescription' => $descriptionRef,
      'url' => $urlRef,
      'title' => 'Churches of India',
      'request.uri_base' => 'http://localhost/',
      'Testing'   => "This is text to test to make sure this will come through", # to test, use this like <% Testing %> on your template page
      };
      
  6. fetchall_href in lib/xxxxxx.pm
    • Select from mysqldb and get the resulting data as a hash
      my $db = connect_db();
      my $sql='SELECT country_id,country_name FROM country';
      my $sth = $db->prepare($sql) or die $db->errstr;
      $sth->execute or die $sth->errstr;
      my $countrynameRef = $sth->fetchall_hashref('country_name');
      
      template 'query5.tt', {
      'countryname' => $countrynameRef,
      'statename' => $statenameRef,
      'cityname' => $citynameRef,
      'churchid' => $churchidRef,
      'feastname' => $feastnameRef,
      'feastdescription' => $descriptionRef,
      'url' => $urlRef,
      'title' => 'Churches of India',
      'request.uri_base' => 'http://localhost/',
      'Testing'   => "This is text to test to make sure this will come through", # to test, use this like <% Testing %> on your template page
       };
      
    • Another example of Select from mysqldb and get the resulting data as a hash
      get '/testarray' => sub {
      my $db = connect_db();
      my $sql='SELECT state_id,state_name FROM state';
      my $sth = $db->prepare($sql) or die $db->errstr;
      $sth->execute or die $sth->errstr;
      
      # build data structure
      my $id;
      my $name;
      my %data;
      while (($id, $name) = $sth->fetchrow_array()) {
      $data{$id} = {
      id => $id,
      name => $name
      }
      }
      $sth->finish;
      
      # build city data structure
      my $sql1='SELECT city_id,city_name FROM city';
      my $sth1 = $db->prepare($sql1) or die $db->errstr;
      $sth1->execute or die $sth1->errstr;
      
      my $id1;
      my $name1;
      my %data1;
      while (($id, $name) = $sth1->fetchrow_array()) {
      $data1{$id} = {
      cityid => $id,
      cityname => $name
      }
      }
      $sth1->finish;
      template 'testarray.tt' => { 'title' => 'church_timing',
      'data' => \%data,
      'data1' => \%data1
      };
      };