As a newbie to Perl I'm struggling to find a simple way to do this. I've created a very simple table in my database:
CREATE TABLE users (
id SERIAL NOT NULL PRIMARY KEY,
username TEXT NOT NULL,
password TEXT NOT NULL);
So far I used a simple login system that has a hard coded username and password that I found online:
package Example;
use Dancer ':syntax';
our $VERSION = '0.1';
set session => "Simple";
get '/' => sub {
# template 'index',{},{layout => 0};
template 'index';
};
before sub {
if (! session('user') && request->path_info !~ m{^/login}) {
var requested_path => request->path_info;
request->path_info('/login');
}
};
get '/login' => sub {
# Display a login page; the original URL they requested is available as
# vars->{requested_path}, so could be put in a hidden field in the form
template 'login', { path => vars->{requested_path} }, {layout => 0};
};
post '/login' => sub {
# Validate the username and password they supplied
if (params->{user} eq 'user' && params->{pass} eq 'letmein') {
session user => params->{user};
redirect params->{path} || '/';
} else {
redirect printf 'login failed';
}
};
get '/logout' => sub {
session->destroy;
redirect '/';
};
How do I get started with linking the database and then matching what the user inputs with what's in the database? And also when do I implement the hashing of the passwords? Any tutorials will be greatly appreciated - I've been using metacpan but it's not providing as much detail as I need!
Dancer::Plugin::Auth::Extensible
takes care of a lot of boilerplate code for you. You can get a simple login system up and running without having to write any of your own /login
routes as follows.
Dancer::Plugin::Auth::Extensible
Install Dancer::Plugin::Database
and Dancer::Plugin::Auth::Extensible::Provider::Database
and add this to config.yml
:
session: "YAML"
plugins:
Auth::Extensible:
realms:
users:
provider: 'Database'
disable_roles: 1
Configure your database connection in environments/development.yml
so that you can have different configurations for dev and production. This is what the configuration looks like for MySQL, with the connection credentials (database name, host, username, and password) stored in a separate options file database.cfg
:
plugins:
Database:
dsn: 'dbi:mysql:;mysql_read_default_file=/path/to/database.cfg'
dbi_params:
RaiseError: 1
AutoCommit: 1
For Postgres, you should use a .pgpass
file to store your connection credentials. Make sure the file is not world readable. See this Stack Overflow post for an example. Test that your credentials file works on the command line and that your webserver can read it.
Your existing table appears to conform to the suggested schema in the docs, but even if it doesn't, you can adjust the table and column names in the configuration.
Add the require_login
keyword to a route you want to protect. A /login
route will be generated automatically with a basic login form, although you can create your own if you like.
lib/MyApp.pm
package MyApp;
use Dancer ':syntax';
use Dancer::Plugin::Auth::Extensible;
our $VERSION = '0.1';
get '/' => require_login sub {
template 'index';
};
true;
(Yes, that really is all the code you have to write. I told you it takes care of a lot of boilerplate.)
Crypt::SaltedHash
is used to hash passwords automatically. Note that you should never store plaintext passwords in your database; when you add a user to your database, you should generate a hash of the password and store the hash.
Note that roles are disabled in this example. If you enable roles, you can do other nifty things like only allow users with the admin role to view admin pages.