毁坏一个会话
When you're done with your session, you can destroy it:
session->destroy
Sessions and logging in ------->会话和登陆
A common requirement is to check the user is logged in, and, if not, require them to log in before continuing.
This can easily be handled with a before hook to check their session:
hook '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} };
};
post '/login' => sub {
# Validate the username and password they supplied
if (params->{user} eq 'bob' && params->{pass} eq 'letmein') {
session user => params->{user};
redirect params->{path} || '/';
} else {
redirect '/login?failed=1';
}
};
In your login page template, you'll want a text field named user, a password field named pass, and a hidden field named path, which will be populated with the path originally requested, so that it's sent back in the POST submission, and can be used by the post route to redirect onwards to the page originally requested once you're logged in.
Of course, you'll probably want to validate your users against a database table, or maybe via IMAP/LDAP/SSH/POP3/local system accounts via PAM etc. Authen::Simple is probably a good starting point here!
A simple working example of handling authentication against a database table yourself (using Dancer::Plugin::Database which provides the database keyword, and Crypt::SaltedHash to handle salted hashed passwords (well, you wouldn't store your users passwords in the clear, would you?)) follows:
post '/login' => sub {
my $user = database->quick_select('users',
{ username => params->{user} }
);
if (!$user) {
warning "Failed login for unrecognised user " . params->{user}; redirect '/login?failed=1';
} else {
if (Crypt::SaltedHash->validate($user->{password}, params->{pass}))
{
debug "Password correct";
# Logged in successfully
session user => $user;
redirect params->{path} || '/';
} else {
debug("Login failed - password incorrect for " . params->{user}); redirect '/login?failed=1';
}
}
};
Retrieve complete hash stored in session
Get complete hash stored in session:
my $hash = session;
APPEARANCE------->页面显示
Using templates - views and layouts
Returning plain content is all well and good for examples or trivial apps, but soon you'll want to use templates to maintain separation between your code and your content. Dancer makes this easy.
Your route handlers can use the template keyword to render templates.
Views
It's possible to render the action's content with a template, this is called a view. The 'appdir/views' directory is the place where views are located.
You can change this location by changing the setting 'views'.
通过views设置来改变视图存储地
By default, the internal template engine Dancer::Template::Simple is used, but you may want to upgrade to Template::Toolkit. If you do so, you have to enable this engine in your settings as explained in Dancer::Template::TemplateToolkit. If you do so, you'll also have to import the Template module in your application code.
Note that, by default, Dancer configures the Template::Toolkit engine to use <% %> brackets instead of its default [% %] brackets. You can change this by using the following in your config file:
template: template_toolkit
engines:
template_toolkit:
start_tag: '[%'
stop_tag: '%]'
All views must have a '.tt' extension. This may change in the future.
In order to render a view, just call the template|Dancer/template keyword at the end of the action by giving the view name and the HASHREF of tokens to interpolate in the view (note that for convenience, the request, session, params and vars are automatically accessible in the view, named request, session, params and vars) - for example:
hook 'before' => sub { var time => scalar(localtime) };
get '/hello/:name' => sub {
my $name = params->{name};
template 'hello.tt', { name => $name };
};
The template 'hello.tt' could contain, for example:
<p>Hi there, <% name %>!</p>
<p>You're using <% request.user_agent %></p>
<% IF session.username %>
<p>You're logged in as <% session.username %>
<% END %>
It's currently <% vars.time %>
For a full list of the tokens automatically added to your template (like session, request and vars, refer to Dancer::Template::Abstract).
Layouts
A layout is a special view, located in the 'layouts' directory (inside the views directory) which must have a token named 'content'. That token marks the place where to render the action view. This lets you define a global layout for your actions, and have each individual view contain only the specific content. This is a good thing to avoid lots of needless duplication of HTML :)
Here is an example of a layout: views/layouts/main.tt :
<html>
<head>...</head>
<body>
<div id="header">
...
</div>
<div id="content">
<% content %>
</div>
</body>
</html>
You can tell your app which layout to use with layout: name in the config file, or within your code:
set layout => 'main';
You can control which layout to use (or whether to use a layout at all) for a specific request without altering the layout setting by passing an options hashref as the third param to the template keyword:
template 'index.tt', {}, { layout => undef };
If your application is not mounted under root (/), you can use a before_template_render hook instead of hardcoding the path to your application for your css, images and javascript:
hook 'before_template_render' => sub {
my $tokens = shift;
$tokens->{uri_base} = request->base->path;
};