Warning! This page has the following tags:
- This page is deprecated, and is only useful for developers using Agavi 0.10.
- This page exists for reference purposes only.
Overview
Agavi comes packaged with credential/permission based authentication via the BasicSecurityUser? class. Before you can implement this, you need to understand how it generally works. This class extends the SecurityUser? class, and provides ways to add/remove and check permissions that the user object possesses. These permissions are stored as session variables or via your selected session storage class. Agavi also has built in support for requiring the user to posess a specific permission when an action is called, which we will cover in detail below.
Logging In
By adding a LoginInputView?, and a LoginInput? template(which posts to itself), then modifying the execute function of the login action, we can set the status of the user to logged in when the correct parameters are set. Here is a simple execute function and that when the user logs in with admin/admin they are authenticated. Also note that you will need to change the accepted request method to POST, and set the default view to INPUT so when a post is recieved the execute command will be executed. See the general Agavi tutorial for more information if this doesn't make sense.
function execute()
{
$request = $this->getContext()->getRequest();
$user = $this->getContext()->getUser();
if($request->getParameter('username') == 'admin' && $request->getParameter('password') == 'admin')
{
$user->setAuthenticated(true);
return View::SUCCESS;
}
return View::ERROR;
}
This only sets the user as authenticated (see Simple Authentication), and does not provide any means of group permissions. If the login is posted as admin/admin then the user will be set as authenticated. It is generally a good idea to also call setAuthenticated(false) when the user tries to login and fails.
Simple Authentication
If you do not need/want group permissions, but just a simple way to manage a logged in/out status which will deny access to an action, we simply add the isSecure() method to the action.
function isSecure()
{
return true;
}
The FrontWebController? will check if the current user is authenticated when this function returns true, and either continue with the action, or call the defined secure action (which by default is SecureAction?). This action is used to inform the user that they need to be logged in to continue, and perhaps show a login form which they can use to login.
Group/Permission Authentication
To require a permission on an action, we simply add the following function to the action to require that the uses possesses the admin credential.
function getCredential()
{
return 'admin';
}
This in effect will be checked when the controller loads this action, and will (by default) call the SecureAction? that will inform them they do not have the credentials required to access this action.
Its most common to use a database for managing users and their credentials. One way, which I implement for group based authentication would require 3 tables. One for users, one for groups, and another table for maintaining group memberships. When we call the execute function we would first query the database to see if a user exists with that password, then query the membership table (joined on the group table) to get a list of groups which that user belongs to. Then applying each one of those permissions to the user. These permissions are maintained until you clear them, or login as a different user (see Logging Out). Below is an example of adding a set of credentials to a user without the use of a database for clarity. Again, it is a good idea to clear and current credentials before you begin adding more.
function execute()
{
$request = $this->getContext()->getRequest();
$user = $this->getContext()->getUser();
$group = array('admin','user','news');
if($request->getParameter('username') == 'admin' && $request->getParameter('password') == 'admin')
{
$user->clearCredentials();
$user->setAuthenticated(true);
foreach($group as $credential)
{
$user->addCredential($credential);
}
return View::SUCCESS;
}
return View::ERROR;
}
Logging Out
The execution of logging a user out is as simple as clearing their credentials, and setting their authenticated status to false.
Tips on Forwarding and Redirecting
Forwarding and redirection can really tie your site together and allow you to do things such as when a user tries to access a protected action they can be shown a 'please login' form, which they login with. By retrieving the first action in the ActionStack? they can be redirected directly back to the page they orignally requested. This makes the whole experience smooth and reduces confusion for users. This same method can be applied when logging out, and redirecting the user to the default index page of your site.
A practical example
Disclaimer: I have just started figuring out Agavi myself. Please correct the following if you find it is wrong or misleading. (and while I have just set up a very similar login, I haven't even run the code examples below. I'll try to do that asap.)
Sice there's so scarce documentation for Agavi, let me attempt to add a practical example to the explanations above. Agavi is a great package which handles all the basic stuff nicely, so you can concentrate on your application's functionality.
Let start with what the user sees - the template, in our case the file has to be called LoginInput?(.php).
<p> <?php echo $template['message'] ?> </p> <form action="/" method="post"> <input name="login[username]" type="text" value="<?php echo $template['username'] ?>"/> <input name="login[password]" type="password"/> <input type="submit" name="submit" value="login"/> </form>
This is, well, a template. no surprises!
Now the Action - LoginAction?. It will receive the Form Data from the above template via the Request object, then decide if the user is allowed in. if yes, it will (in my example) forward to the first "logged in" page of the application, Default_IndexAction. if no, it will show the login form again.
class Default_LoginAction extends Action
{
function execute()
{
// request contains data submitted from the login form; in our case an
// array: login[username] and login[password]
$request = $this->getContext()->getRequest();
// the user stores authentication data persistently across several requests
$user = $this->getContext()->getUser();
// check if username and password are valid for logging in; see next method.
if ($this->validateUser($request->getParameter('login'))) {
// remember that the current user is authenticated
$user->setAuthenticated(true);
// this action has done it's job. now that the user is logged in,
// let the default action take over and do whatever it needs to do ...
$controller = $this->getContext()->getController();
$controller->forward('Default', 'Index');
// tell agavi that this action doesnt produce any output.
return View::NONE;
} else {
// not authenticated
$user->setAuthenticated(false);
return View::INPUT;
}
}
/**
* @param array $login login-data from the form
*
*/
private function validateUser($login)
{
// do fancy database user lookup / ldap whatever stuff here ...
return ($login['username'] == 'admin' && $login['password'] == 'admin');
}
public function getDefaultView()
{
return View::INPUT;
}
public function getRequestMethods()
{
return Request::POST;
}
}
Finally the view. It will read out the information LoginAction? has put into the Request object and fill it into the template shown above.
LoginInputView? also is the default View configured by LoginAction? in its method getDefaultView(), so it will also be used for display the first time LoginAction? is run.
class Default_LoginInputView extends PHPView
{
public function execute ()
{
// the template to use, see above.
$this->setTemplate('LoginInput.php');
// tell the user what's wrong. the action already handled that, just pass it's result on to the template
$request = $this->getContext()->getRequest();
$this->setAttribute('message', $request->getAttribute('message'));
// preserve the username.
$loginData = $request->getParameter('login');
// @self: figure out the difference between parameters and attributes ...
$this->setAttribute('username', $loginData['username']);
}
}
If all the above three are in place, you can add a
function isSecure()
{
return true;
}
to all the actions you want to protect. If an unauthorized user tries to access one of these, Agavi will automatically redirect people to the login page we just built. After they successfully logged in, you can either take them to an action you would like them to see (in my case Index)
$controller = $this->getContext()->getController();
$controller->forward('Default', 'Index');
or you can analyze the ActionStack? to find out where people came from in the first place and send them there:
$controller = $this->getContext()->getController(); $actionStack = $controller->getActionStack(); // ... havent been able to figure that one out ...
nice, huh?

