Embedding Perl in HTML with Mason Chapter 11: Recipes- P2

Chia sẻ: Thanh Cong | Ngày: | Loại File: PDF | Số trang:16

lượt xem

Embedding Perl in HTML with Mason Chapter 11: Recipes- P2

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Tham khảo tài liệu 'embedding perl in html with mason chapter 11: recipes- p2', công nghệ thông tin, kỹ thuật lập trình phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả

Chủ đề:

Nội dung Text: Embedding Perl in HTML with Mason Chapter 11: Recipes- P2

  1. Chapter 11: Recipes- P2 Making Use of Autoflush Every once in a while you may have to output a very large component or file to the client. Simply letting this accumulate in the buffer could use up a lot of memory. Furthermore, the slow response time may make the user think that the site has stalled. Example 11-4 sends out the contents of a potentially large file without sucking up lots of memory. Example 11-4. send_file-autoflush.comp $filename local *FILE; open FILE, "< $filename" or die "Cannot open $filename: $!"; $m->autoflush(1); while () { $m->print($_); } $m->autoflush(0);
  2. If each line wasn't too huge, you might just flush the buffer every once in a while, as in Example 11-5. Example 11-5. send_file-flush-every-10.comp $filename local *FILE; open FILE, "< $filename" or die "Cannot open $filename: $!"; while () { $m->print($_); $m->flush_buffer unless $. % 10; } $m->flush_buffer; The unless $. % 10 bit makes use of the special Perl variable $., which is the current line number of the file being read. If this number modulo 10 is equal to zero, we flush the buffer. This means that we flush the buffer every 10 lines. Replace the number 10 with any desired value. User Authentication and Authorization
  3. One problem that web sites have to solve over and over is user authentication and authorization. These two topics are related but not the same, as some might think. Authentication is the process of figuring out if someone is who he says he is, and usually involves checking passwords or keys of some sort. Authorization comes after this, when we want to determine whether or not a particular person is allowed to perform a certain action. There are a number of modules on CPAN intended to help do these things under mod_perl. In fact, Apache has separate request-handling phases for both authentication and authorization that mod_perl can handle. It is certainly possible to use these modules with Mason. You can also do authentication and authorization using Mason components (as seen in Chapter 8). Authentication will usually involve some sort of request for a login and password, after which you give the user some sort of token (either in a cookie or a session) that indicates that he has been authenticated. You can then check the validity of this token for each request. If you have such a token, authorization simply consists of checking that the user to whom the token belongs is allowed to perform a given action. Using Apache::AuthCookie The Apache::AuthCookie module, available from CPAN, handles both authentication and authorization via mod_perl and can be easily hooked into Mason. Let's just skip all the details of configuring Apache::AuthCookie, which requires various settings in your server config file, and show how to make the interface to Mason.
  4. Apache::AuthCookie requires that you create a "login script" that will be executed the first time a browser tries to access a protected area. Calling this a script is actually somewhat misleading since it is really a page rather than a script (though it could be a script that generates a page). Regardless, using a Mason component for your login script merely requires that you specify the path to your Mason component for the login script parameter. We'll call this script AuthCookieLoginForm-login.comp,as shown in Example 11-6. Example 11-6. AuthCookieLoginForm-login.comp Mason Book AuthCookie Login Form Your attempt to access this document was denied (prev->subprocess_env("AuthCookieReason") %>). Please enter your username and password.
  5. Username: Password:
  6. This component is a modified version of the example login script included with the Apache::AuthCookie distribution. The action used for this form, /AuthCookieLoginSubmit, is configured as part of your AuthCookie configuration in your httpd.conf file. That is about it for interfacing this module with Mason. The rest of authentication and authorization is handled by configuring mod_perl to use Apache::AuthCookie to protect anything on your site that needs authorization. A very simple configuration might include the following directives: PerlSetVar MasonBookLoginScript /AuthCookieLoginForm.comp AuthType MasonBook::AuthCookieHandler AuthName MasonBook SetHandler perl-script PerlHandler MasonBook::AuthCookieHandler->login AuthType MasonBook::AuthCookieHandler AuthName MasonBook
  7. PerlAuthenHandler MasonBook::AuthCookieHandler- >authenticate PerlAuthzHandler MasonBook::AuthCookieHandler- >authorize require valid-user The MasonBook::AuthCookieHandler module would look like this: package MasonBook::AuthCookieHandler; use strict; use base qw(Apache::AuthCookie); use Digest::SHA1; my $secret = "You think I'd tell you? Hah!"; sub authen_cred { my $self = shift; my $r = shift; my ($username, $password) = @_;
  8. # implementing _is_valid_user() is out of the scope of this chapter if ( _is_valid_user($username, $password) ) { my $session_key = $username . '::' . Digest::SHA1::sha1_hex( $username, $secret ); return $session_key; } } sub authen_ses_key { my $self = shift; my $r = shift; my $session_key = shift; my ($username, $mac) = split /::/, $session_key; if ( Digest::SHA1::sha1_hex( $username, $secret ) eq $mac ) { return $session_key; } }
  9. This provides the minimal interface an Apache::AuthCookie subclass needs to provide to get authentication working. Authentication Without Cookies But what if you don't want to use Apache::AuthCookie? Your site may need to work without using cookies. First, we will show an example authentication system that uses only Mason and passes the authentication token around via the URL (actually, via a session). This example assumes that we already have some sort of session system that passes the session ID around as part of the URL, as discussed previously. We start with a quick login form. We will call this component login_form.html, as shown in Example 11-7. Example 11-7. login_form.html $username => '' $password => '' $redirect_to => '' @errors => ( ) Mason Book Login
  10. % if (@errors) { Errors % foreach (@errors) { % } % } Login: Password:
  11. This form uses some of the same techniques we saw in Chapter 8 to prepopulate the form and handle errors. Now let's make the component that handles the form submission. This component, called login_submit.html and shown in Example 11-8, will check the username and password and, if they are valid, place an authentication token into the user's session. Example 11-8. login_submit.html $username $password $redirect_to
  12. if (my @errors = check_login($username, $password) { $m->comp( 'redirect.mas', path => 'login_form.html', query => { errors => \@errors, username => $username, password => $password, redirect_to => $redirect_to } ); } $MasonBook::Session{username} = $username; $MasonBook::Session{token} = Digest::SHA1::sha1_hex( 'My secret phrase', $username ); $m->comp( 'redirect.mas', path => $redirect_to ); This component simply checks (via magic hand waving) whether the username and password are valid and, if so, generates an authentication
  13. token that is added to the user's session. To generate this token, we take the username, which is also in the session, and combine it with a secret phrase. We then generate a MAC from those two things. The authentication and authorization check looks like this: if ( $MasonBook::Session{token} ) { if ( $MasonBook::Session{token} eq Digest::SHA1::sha1_hex( 'My secret phrase', $MasonBook::Session{username} ) { # ... valid login, do something here } else { # ... someone is trying to be sneaky! } } else { # no token my $wanted_page = $r->uri; # Append query string if we have one. $wanted_page .= '?' . $r->args if $r->args; $m->comp( 'redirect.mas',
  14. path => '/login/login_form.html', query => { redirect_to => $wanted_page } ); } We could put all the pages that require authorization in a single directory tree and have a top-level autohandler in that tree do the check. If there is no token to check, we redirect the browser to the login page, and after a successful login the user will return, assuming she submitted valid login credentials. Access Controls with Attributes The components we saw previously assumed that there are only two access levels, unauthenticated and authenticated. A more complicated version of this code might involve checking that the user has a certain access level or role. In that case, we'd first check that we had a valid authentication token and then go on to check that the user actually had the appropriate access rights. This is simply an extra step in the authorization process. Using attributes, we can easily define access controls for different portions of our site. Let's assume that we have four access levels, Guest, User, Editor, and Admin. Most of the site is public and viewable by anyone. Some parts of the site require a valid login, while some require a higher level of privilege. We implement our access check in our top-level autohandler, /autohandler, from which all other components must inherit in order for the access control code to be effective.
  15. my $user = get_user( ); # again, hand waving my $required_access = $m->base_comp- >attr('required_access'); unless ( $user- >has_access_level($required_access) ) { # ... do something like send them to another page } $m->call_next; required_access => 'Guest' It is crucial that we set a default access level in this autohandler. By doing this, we are saying that, by default, all components are accessible by all people, since every visitor will have at least Guest access. We can override this default elsewhere. For example, in a component called /admin/autohandler, we might have:
  16. required_access => 'Admin' As long as all the components in the /admin/ directory inherit from the /admin/autohandler component and don't override the required_access attribute, we have effectively limited that directory (and its subdirectories) to admin users only. If we for some reason had an individual component in the /admin/ directory that we wanted editors to be able to see, we could simply set the required_access attribute for that component to 'Editor' . Co-Branding Color Schemes One common business practice these days is to take a useful site and offer "cobranded" versions of it to other businesses. A co-branded site might display different graphics and text for each client while retaining the same basic layout and functionality across all clients. Mason is extremely well-suited to this task. Let's look at how we might apply a new color scheme to each co-brand. For the purpose of these examples, we're going to assume that the name of the co-brand has already been determined and is being passed to our components as a variable called $cobrand. This variable could be set up by including the co-brand in the query string, in a session, or as part of a hostname.
Đồng bộ tài khoản