Hallo zusammen,
ich habe vor knapp 2 Wochen ein Auth Modul auf Basis von Zend Framework erweitert, bin aber Designtechnisch noch nicht ganz zufrieden und wollte nachfragen, ob und was ich besser machen kann.
Einstiegspunkt ist ein Plugin im Dispatchloop:
Das Plugin wiederum ruft Bos_Auth auf, die über statische Methoden die Abhängigkeiten mappt. Auch hier die Frage, ob ihr das anders lösen würdet und wenn ja, wieso?
Hier die abstrakte Parentclass des Auth Moduls, von der alle erben:
Problem ist dabei im Besonderen, dass $request->getControllerName() im default module "Controllernamen" enthält, die dabei alle auf einen Controller geroutet werden, um eine bestimmte Seite mit verschiedenen Inhalten anzeigen zu können. In dem Fall Bandprofile einer Community Page.
Hier der Vollständigkeit halber noch das Default Module:
Kritik und Anregungen erwünscht
ich habe vor knapp 2 Wochen ein Auth Modul auf Basis von Zend Framework erweitert, bin aber Designtechnisch noch nicht ganz zufrieden und wollte nachfragen, ob und was ich besser machen kann.
Einstiegspunkt ist ein Plugin im Dispatchloop:
PHP-Code:
/**
* checks if user has permisson to view page
* - logs user in
* - gets user role
* - checks acl
*
* @see Bos_Auth
* @see Zend_Auth
* @see ErrorController
* @param object Zend_Controller_Request_Abstract $request
*/
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
$action = $request->getActionName();
$controller = $request->getControllerName();
$module = $request->getModuleName();
if($action === "logout" && $controller == "login") {
Bos_Auth::logout($request);
}
if($controller == "login" && $action == "login") {
Bos_Auth::identify($request, $module);
}
// Lade aktuelle Rolle aus der Identität (falls vorhanden)
$role = $this->_getRole($request);
/**
* !!! refresh, da evtl durch Auth geändert !!!
*/
$module = $request->getModuleName();
$controller = $request->getControllerName();
$action = $request->getActionName();
// fallback
if(empty($role)) {
$role = "guest";
}
// Hole ACL für Modul
$acl = Bos_Acl::getInstance($module);
// Prüfe Rechte
if (!$acl->isAllowed
(
$role,
$controller,
$action
)
)
{
if("development" == APPLICATION_ENVIRONMENT) {
Debug::dump("access denied", $request, $role);
}
$request->setModuleName('default');
$request->setControllerName('error');
$request->setActionName('not-found');
}
}
PHP-Code:
/**
* @author Sebastian Sauer <info klammeraffe dynpages.de>
* @copyright Sebastian Sauer 2009/2010
* @package auth
* @version 1.2
*/
class Bos_Auth {
/**
* creates instances of auth module regarding to the module
* encapsulate dependencies of Bos_Auth_Abstract
* @param object Zend_Controller_Request_Abstract $request
* @param $module [optional]
* @return object Bos_Auth_Abstract
*/
private static function _getAuthObject ($request, $module = "") {
if(empty($module)) {
$module = $request->getModuleName();
}
require_once APPLICATION_PATH . '/../library/Bos/Controller/Action/Helper/Notify.php';
$notify = new Helper_Notify();
switch ($module) {
case "customer" :
case "admin" :
case "default":
$class = "Bos_Auth_" . ucfirst ($module);
$auth = new $class ($request, $notify);
break;
default:
$auth = new Bos_Auth_Default($request, $notify);
break;
}
return $auth;
}
/**
* user login
* @param object Zend_Controller_Request_Abstract $request
* @param $module [optional]
*/
public static function identify(Zend_Controller_Request_Abstract $request, $module = "") {
$auth = self::_getAuthObject($request, $module);
$auth->identify();
}
/**
* user logout
* @param object Zend_Controller_Request_Abstract $request
*/
public static function logout (Zend_Controller_Request_Abstract $request) {
$auth = self::_getAuthObject($request);
$auth->logout();
}
/**
* get user role by module
* @param object Zend_Controller_Request_Abstract $request
*/
public static function getRole (Zend_Controller_Request_Abstract $request) {
$auth = self::_getAuthObject($request);
return $auth->getRole();
}
}
PHP-Code:
<?php
/**
* @author Sebastian Sauer <info klammeraffe dynpages.de>
* @copyright Sebastian Sauer 2009/2010
* @package auth
* @version 1.3
*/
abstract class Bos_Auth_Abstract {
protected $_request;
/**
* database table name
* @var string
*/
protected $_authTable = "";
/**
* database table userfield field name
* @var string
*/
protected $_userField = "";
/**
* database table password field name
* @var string
*/
protected $_passwordField = "";
/**
* database table password salt field name
* @var string
*/
protected $_passwordSaltField = "password_salt";
/**
* message templating namespace
*
* @var object Helper_Notify
*/
protected $_notify;
/**
* cache auth adapter object for child classes
* @var object Zend_Auth_Adapter_DbTable
*/
private $_authAdapter = null;
const storageModuleAppendix = "AuthStorage";
/**
* login user
*/
public function identify() {
$request = $this->_request;
$post = $request->getPost();
$username = $this->_filterUsername($post['username']);
$password = $post['password'];
if(empty($username) || empty($password)) {
return;
}
$this->_doAuth($username, $password);
}
abstract public function getRole();
/**
* @param object Zend_Controller_Request_Abstract $request
*/
public function __construct(
Zend_Controller_Request_Abstract $request,
Zend_Controller_Action_Helper_Abstract $notify
) {
$this->_request = $request;
$auth = Zend_Auth::getInstance();
$module = (null === $request->getModuleName())
? 'default'
: $request->getModuleName();
$namespace = $module . self::storageModuleAppendix;
$auth->setStorage(new Zend_Auth_Storage_Session($namespace));
$this->_notify = $notify;
}
/**
* getter for auth adapter object
*
* @return object Zend_Auth_Adapter_DbTable
*
* Initialisiere Authentifizierungsadapter
* gesaltet! bootstrapping beachten
* Führe Authentifizierung durch
*/
protected function _getAuthAdapter () {
if(is_null($this->_authAdapter)) {
$authAdapter = $this->_authAdapter = new Zend_Auth_Adapter_DbTable(
Zend_Registry::get('Zend_Db'),
$this->_authTable,
$this->_userField,
$this->_passwordField,
"MD5(
CONCAT('"
. Zend_Registry::get('staticSalt')
. "', password_salt, ?
)
)"
);
}
return $this->_authAdapter;
}
/**
* filters Username
* @see Zend_Filter_Alnum
* @param string $username
*/
protected function _filterUsername ($username) {
$filter = new Zend_Filter_Alnum(true);
return $filter->filter($username);
}
public function logout() {
Zend_Auth::getInstance()->clearIdentity();
unset($_SESSION);
// tweak the garbage collector
$_SESSION = null;
}
/**
* check if username / password combination exists in database
* sets storage data if auth is valid
* @return bool
*/
protected function _doAuth($username, $password) {
$authAdapter = $this->_getAuthAdapter();
// Übergebe Daten an Adapter
$authAdapter->setIdentity($username);
$authAdapter->setCredential($password);
$result = Zend_Auth::getInstance()->authenticate($authAdapter);
if($result->isValid()) {
$authData = $authAdapter->getResultRowObject();
unset(
$authData->{$this->_passwordField},
$authData->{$this->_passwordSaltField}
);
Zend_Auth::getInstance()->getStorage()->write
(
$authData
);
}
return $result->isValid();
}
}
Hier der Vollständigkeit halber noch das Default Module:
PHP-Code:
<?php
/**
* @author Sebastian Sauer <info klammeraffe dynpages.de>
* @copyright Sebastian Sauer 2009/2010
* @package auth
* @version 1.3
*
* TODO:
* - provide system notifications for banned / deactivated users
* @see databaste table t_user_main.sStatus enum('DELETED','BANNED','PENDING','ACTIVE')
*
*/
class Bos_Auth_Default extends Bos_Auth_Abstract {
/**
* database table name
* @var string
*/
protected $_authTable = "t_user_main";
/**
* database table userfield field name
* @var string
*/
protected $_userField = "sUsername";
/**
* database table password field name
* @var string
*/
protected $_passwordField = "sPassword";
/**
* @var object Zend_Session_Namespace
*/
protected $_session = null;
/**
* All controllers of default module
* @see Bos_Config
* @var array
*/
private $_controllers = null;
/**
* @return object instance of Zend_Session
*/
protected function _getSessionNamespace ()
{
if($this->_session === null) {
$this->_session = new Zend_Session_Namespace("UserData");
}
return $this->_session;
}
/**
* just a bit tricky mapping:
* this one is written to access bands direct by url/bandname
* @see BandController index action
* @return string controller name
*/
private function _getController ()
{
$request = $this->_request;
$controller = $request->getControllerName();
if(is_null($this->_controllers)) {
$this->_controllers = Bos_Config::getInstance()->getControllers();
}
if(!in_array(strtolower($controller), $this->_controllers))
{
$request->setControllerName('band');
$request->setActionName('index');
return 'band';
}
return $controller;
}
/**
* @see Bos_BandControllers
* @return void
*/
private function _checkAuthForBandController ()
{
$session = $this->_getSessionNamespace();
$id_band = intval($this->_request->getParam("id"));
if($id_band > 0) {
foreach($session->bandset as $index => $band) {
if($id_band === (int)$band->nId) {
return $band->sRole;
}
}
} else if(!empty($_SESSION["BandController"])) {
foreach($session->bandset as $index => $band) {
if($_SESSION["BandController"]["BandId"] === (int)$band->nId) {
return $band->sRole;
}
}
}
return "registered";
}
protected function _valid() {}
/**
* provide a nice message if login was invalid - kill identity
* @see Bos_SystemMessages
*/
protected function _invalid () {
$notify = $this->_notify;
$notify->prependHl = "Anmeldung fehlgeschlagen.";
$notify->attach = array(
"Benutzer oder Passwort inkorrekt oder Benutzer existiert nicht.",
"Bitte probiere es noch einmal."
);
Zend_Auth::getInstance()->clearIdentity();
}
/**
* user registered - but still pending. Redirect him and remove his auth
* TODO: give user ability to input his email address
* @return void
*/
private function _pending () {
$notify = $this->_notify;
$request = $this->_request;
// messages
$notify->prependHl = "Bitte aktiviere deinen Account.";
$notify->attach = array(
"Solltest du <strong>keine</strong> Aktivierungs-Mail bekommen haben,kontaktiere bitte unser Team.",
"Wir helfen dir dann so schnell wie möglich weiter."
);
// kill identity
Zend_Auth::getInstance()->clearIdentity();
// redirect
$request->setModuleName('default');
$request->setControllerName('register');
$request->setActionName('activate');
}
/**
* @return void
*/
public function identify () {
$request = $this->_request;
$post = $request->getPost();
$username = $this->_filterUsername($post['username']);
$password = $post['password'];
if(empty($username) || empty($password)) {
return $this->_invalid();
}
$auth = Zend_Auth::getInstance();
if (false === $this->_doAuth($username, $password)) {
return $this->_invalid();
}
$stat = $auth->getStorage()->read()->sStatus;
$session = $this->_getSessionNamespace();
if ($stat == "PENDING") {
return $this->_pending();
}
// Authentifizierung war erfolgreich
$identity = $auth->getIdentity();
$users = new Users();
/**
* für acl band rolle speichern
* alle Banddaten in Session persistent ablegen:
*/
$session->bandset = $users -> fetchBandProperties (
$username
);
Zend_Registry::set('UserData', $session);
$this->_valid();
}
/**
* @return string
*/
public function getRole() {
$controller = $this->_getController();
$auth = Zend_Auth::getInstance();
if(false === $auth->hasIdentity()) {
return 'guest';
}
User::getInstance()->writeLastSeen();
if("band" == $controller || "bandmedia" == $controller || "bandsettings" == $controller) {
return $this->_checkAuthForBandController();
} else {
return "registered";
}
}
}
Kommentar