Vegas CMF provides two authentication adapters
composer.json
"vegas-cmf/auth" : "dev-master"
php composer.phar update
Standard adapter provides a default method of authentication process, where user authenticates himself using his identity and password.
Follow the 9 steps to see how to setup authentication process in your project.
touch app/services/AuthServiceProvider.php
use Phalcon\DiInterface;
use Phalcon\Mvc\Url as UrlResolver;
use Vegas\DI\ServiceProviderInterface;
class AuthServiceProvider implements ServiceProviderInterface
{
const SERVICE_NAME = 'auth';
/**
* {@inheritdoc}
*/
public function register(DiInterface $di)
{
$di->set(self::SERVICE_NAME, function () use ($di) {
$adapter = new \Vegas\Security\Authentication\Adapter\Standard($di->get('userPasswordManager'));
$adapter->setSessionStorage($di->get('sessionManager')->createScope('auth'));
$auth = new \Vegas\Security\Authentication($adapter);
return $auth;
}, true);
}
/**
* {@inheritdoc}
*/
public function getDependencies()
{
return array(
SessionManagerServiceProvider::SERVICE_NAME,
UserPasswordManagerServiceProvider::SERVICE_NAME
);
}
}
SessionServiceProvider
and SessionManagerServiceProvider
to enable session management in your application.
touch app/services/SessionServiceProvider.php
use Phalcon\DiInterface;
use Vegas\DI\ServiceProviderInterface;
use Vegas\Session\Adapter\Files as SessionAdapter;
class SessionServiceProvider implements ServiceProviderInterface
{
const SERVICE_NAME = 'session';
/**
* {@inheritdoc}
*/
public function register(DiInterface $di)
{
$config = $di->get('config');
$di->set(self::SERVICE_NAME, function () use ($config) {
$sessionAdapter = new SessionAdapter($config->session->toArray());
if (!$sessionAdapter->isStarted()) {
$sessionAdapter->start();
}
return $sessionAdapter;
}, true);
}
/**
* {@inheritdoc}
*/
public function getDependencies()
{
return array();
}
}
touch app/services/SessionManagerServiceProvider.php
use Phalcon\DiInterface;
use Vegas\DI\ServiceProviderInterface;
class SessionManagerServiceProvider implements ServiceProviderInterface
{
const SERVICE_NAME = 'sessionManager';
/**
* {@inheritdoc}
*/
public function register(DiInterface $di)
{
$di->set(self::SERVICE_NAME, function() use ($di) {
$session = new Vegas\Session($di->get('session'));
return $session;
}, true);
}
/**
* {@inheritdoc}
*/
public function getDependencies()
{
return array(
SessionServiceProvider::SERVICE_NAME
);
}
}
app/config/config.php
file.
'session' => array(
'cookie_name' => 'sid',
'cookie_lifetime' => 36*3600, //day and a half
'cookie_secure' => 0,
'cookie_httponly' => 1
)
touch app/services/UserPasswordManagerServiceProvider.php
use Phalcon\DiInterface;
use Vegas\DI\ServiceProviderInterface;
class UserPasswordManagerServiceProvider implements ServiceProviderInterface
{
const SERVICE_NAME = 'userPasswordManager';
/**
* {@inheritdoc}
*/
public function register(DiInterface $di)
{
$di->set(self::SERVICE_NAME, '\Vegas\Security\Password\Adapter\Standard', true);
}
/**
* {@inheritdoc}
*/
public function getDependencies()
{
return array();
}
}
mkdir -p app/modules/Auth
mkdir -p app/modules/Auth/config
mkdir -p app/modules/Auth/controllers
mkdir -p app/modules/Auth/controllers/frontend
mkdir -p app/modules/Auth/models
mkdir -p app/modules/Auth/services
mkdir -p app/modules/Auth/views
Module.php
file to enable module
touch app/modules/Auth/Module.php
namespace Auth;
class Module extends \Vegas\Mvc\ModuleAbstract
{
public function __construct() {
$this->namespace = __NAMESPACE__;
$this->dir = __DIR__;
}
}
touch app/modules/Auth/models/User.php
namespace Auth\Models;
class User extends CollectionAbstract implements GenericUserInterface
{
public function getSource()
{
return 'vegas_users';
}
public function beforeSave()
{
if (!empty($this->raw_password)) {
$this->writeAttribute('password', $this->getDI()->get('userPasswordManager')->encryptPassword($this->raw_password));
unset($this->raw_password);
}
}
public function getIdentity()
{
return $this->readAttribute('email');
}
public function getCredential()
{
return $this->readAttribute('password');
}
public function getAttributes()
{
$userData = $this->toArray();
//remove password from user data
unset($userData['password']);
$userData['id'] = $this->getId();
return $userData;
}
}
namespace Auth\Models;
class User extends ModelAbstract implements GenericUserInterface
{
public function getSource()
{
return 'vegas_users';
}
public function beforeSave()
{
if (!empty($this->raw_password)) {
$this->writeAttribute('password', $this->getDI()->get('userPasswordManager')->encryptPassword($this->raw_password));
unset($this->raw_password);
}
}
public function getIdentity()
{
return $this->readAttribute('email');
}
public function getCredential()
{
return $this->readAttribute('password');
}
public function getAttributes()
{
$userData = $this->toArray();
//remove password from user data
unset($userData['password']);
$userData['id'] = $this->getId();
return $userData;
}
}
CREATE TABLE vegas_users(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(100) NOT NULL,
password VARCHAR(200) NOT NULL,
name VARCHAR(50) NOT NULL
);
GenericUserInterface
interface.
touch app/modules/Auth/services/Auth.php
namespace Auth\Services;
use Auth\Models\User;
/**
* Class Auth
* @package Auth\Services
*/
class Auth implements \Phalcon\DI\InjectionAwareInterface
{
use \Vegas\DI\InjectionAwareTrait;
/**
* Authenticates user by email and password
*
* @param $email
* @param $password
* @throws \Vegas\Security\Authentication\Exception\IdentityNotFoundException
*/
public function login($email, $password)
{
$user = User::findFirst(array(array('email' => $email)));
if (!$user) {
throw new \Vegas\Security\Authentication\Exception\IdentityNotFoundException();
}
$this->di->get('auth')->authenticate($user, $password);
}
/**
* Ends session
*/
public function logout()
{
$this->di->get('auth')->logout();
}
}
touch app/modules/Auth/controllers/frontend/AuthController.php
namespace Auth\Controllers\Frontend;
/**
* Class AuthController
*
* @package Auth\Controllers\Frontend
*/
class AuthController extends \Vegas\Mvc\Controller\ControllerAbstract
{
/**
* @return \Phalcon\Http\Response|\Phalcon\Http\ResponseInterface
*/
public function loginAction()
{
$this->view->setLayout('login');
$this->service = $this->serviceManager->getService('auth:auth');
if ($this->di->get('auth')->isAuthenticated()) {
return $this->response->redirect(array('for' => 'root'));
}
if ($this->request->isPost()) {
try {
$email = $this->request->getPost('email');
$password = $this->request->getPost('password');
//authenticates user
$this->service->login($email, $password);
return $this->response->redirect(array('for' => 'root'));
} catch (\Vegas\Security\Authentication\Exception $ex) {
$this->flash->error($this->i18n->_($ex->getMessage()));
}
}
}
/**
* @return \Phalcon\Http\Response|\Phalcon\Http\ResponseInterface
*/
public function logoutAction()
{
$this->view->disable();
$authService = $this->serviceManager->getService('auth:auth');
$authService->logout();
return $this->response->redirect(array('for' => 'login'));
}
}
Auth
to authenticate user by email and password.
touch app/modules/Auth/config/routes.php
return array(
'login' => array(
'route' => '/login',
'paths' => array(
'module' => 'Auth',
'controller' => 'Frontend\Auth',
'action' => 'login',
'auth' => false
),
'type' => 'static'
),
'logout' => array(
'route' => '/logout',
'paths' => array(
'module' => 'Auth',
'controller' => 'Frontend\Auth',
'action' => 'logout',
'auth' => 'auth'
),
'type' => 'static'
)
);
logout
route, we set auth
key with value auth, so before dispatch this action,
SecurityPlugin
will check if user is authenticated in scope auth.
touch app/plugins/SecurityPlugin.php
class SecurityPlugin extends \Vegas\Security\Authentication\EventsManager\Plugin
{
}
SecurityPlugin
add the following code to app/config/config.php
file.
'plugins' => array(
'security' => array(
'class' => 'SecurityPlugin',
'attach' => 'dispatch'
)
)
SecurityPlugin
requires also route configuration, that determines where user should be redirected when required session does not exist.
touch app/modules/Auth/config/config.php
return array(
'auth' => array(
//name of authentication scope
'auth' => array(
//route name
'route' => 'login'
)
)
);
touch app/layouts/login.volt
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="http://getbootstrap.com/assets/ico/favicon.ico">
<title>Login into VEGAS</title>
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="http://getbootstrap.com/examples/signin/signin.css" rel="stylesheet">
<!--[if lt IE 9]><script src="http://getbootstrap.com/assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
{{ assets.outputCss() }}
{{ assets.outputJs() }}
</head>
<body>
<div class="container">
{{ content() }}
</div>
</body>
</html>
touch app/modules/Auth/views/frontend/auth/login.volt
{{ flash.output() }}
<form class="form-signin" role="form" method="POST">
<h2 class="form-signin-heading">Please sign in</h2>
<input type="email" class="form-control" placeholder="Email address" name="email" required autofocus>
<input type="password" class="form-control" placeholder="Password" name="password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
touch app/tasks/UserTask.php
class UserTask extends \Vegas\Cli\Task
{
/**
* Available options
*
* @return mixed
*/
public function setOptions()
{
$action = new \Vegas\Cli\Task\Action('create', 'Create user account');
$option = new \Vegas\Cli\Task\Option('email', 'e', 'User email address');
$option->setRequired(true);
$action->addOption($option);
$option = new \Vegas\Cli\Task\Option('password', 'p', 'User password');
$option->setRequired(true);
$action->addOption($option);
$option = new \Vegas\Cli\Task\Option('name', 'n', 'User name');
$option->setRequired(true);
$action->addOption($option);
$this->addTaskAction($action);
}
public function createAction()
{
$user = new \Auth\Models\User();
$user->email = $this->getOption('email');
$user->raw_password = $this->getOption('password');
$user->name = $this->getOption('name');
$user->save();
$this->putSuccess('User created');
$this->pubObject($user->toArray());
$this->putText('Done.');
}
}
php cli/cli.php app:user create --email=test@vegas.com --password=p@$$w0rd --name=Test
No credential adapter might be useful when we need to have a possibility to login as another user, without knowing his password,
for example in administrator panel.
Use the structure from the previous example, and create new service.
touch app/modules/Auth/services/AuthEmail.php
namespace Auth\Services;
use Auth\Models\User;
use Vegas\Security\OAuth\Exception\ServiceNotFoundException;
/**
* Class AuthEmail
* @package Auth\Services
*/
class AuthEmail implements \Phalcon\DI\InjectionAwareInterface
{
use \Vegas\DI\InjectionAwareTrait;
/**
* Authenticates user by e-mail address
*
* @param $email
* @return mixed
* @throws \Vegas\Security\Authentication\Exception\IdentityNotFoundException
*/
public function authenticateByEmail($email)
{
$user = User::findFirst(array(array('email' => $email)));
if (!$user) {
throw new \Vegas\Security\Authentication\Exception\IdentityNotFoundException();
}
$adapter = new \Vegas\Security\Authentication\Adapter\NoCredential();
$adapter->setSessionStorage($this->obtainSessionScope());
$auth = new \Vegas\Security\Authentication($adapter);
$auth->authenticate($user, null);
return $auth->getIdentity();
}
/**
* Obtains session scope for authentication
* It safely checks if the session scope with 'auth' name already exists
*
* @return mixed
*/
private function obtainSessionScope()
{
$sessionManager = $this->di->get('sessionManager');
if (!$sessionManager->scopeExists('auth')) {
$sessionScope = $sessionManager->createScope('auth');
} else {
$sessionScope = $sessionManager->getScope('auth');
}
return $sessionScope;
}
}
AuthController
for example in Backend scope, to authenticate users by theirs e-mail.
touch app/modules/Auth/controllers/backend/AuthController.php
namespace Auth\Controllers\Backend;
use Vegas\Mvc\Controller\ControllerAbstract;
/**
* Class AuthController
* @package Auth\Controllers\Backend
*/
class AuthController extends ControllerAbstract
{
/**
* @return \Phalcon\Http\Response|\Phalcon\Http\ResponseInterface
*/
public function authenticateUserAction()
{
$this->view->disable();
if ($this->request->isPost()) {
try {
$service = $this->serviceManager->getService('auth:auth');
$service->authenticateByEmail($this->request->get('email'));
return $this->response->redirect(array('for' => 'root'));
} catch (\Vegas\Security\Authentication\Exception $ex) {
$this->flash->error($this->i18n->_($ex->getMessage()));
}
}
}
/**
* @return \Phalcon\Http\Response|\Phalcon\Http\ResponseInterface
*/
public function logoutUserAction()
{
$this->view->disable();
$authService = $this->serviceManager->getService('auth:auth');
$authService->logout();
return $this->response->redirect(array('for' => 'root'));
}
}
app/modules/Auth/config/routes.php
//....
'authenticateUser' => array(
'route' => '/admin/authenticateUser',
'paths' => array(
'module' => 'Auth',
'controller' => 'Backend\Auth',
'action' => 'authenticateUser',
'auth' => 'authAdmin'
),
'type' => 'static'
),
'logoutUser' => array(
'route' => '/admin/logoutUser',
'paths' => array(
'module' => 'Auth',
'controller' => 'Backend\Auth',
'action' => 'logoutUser',
'auth' => 'auth'
),
'type' => 'static'
)
//...
NoCredential
adapter should not be use as public authenticator, that's why authAdmin
authentication scope is required by this action.
/admin/authenticateUser/test@test.com
where test@test.com
belongs to user who will be authenticated.