Zend Framework 2 - 用户身份验证和角色控制(未测试) Authentication + Acl using EventManager

参考:http://p0l0.binware.org/index.php/2012/02/18/zend-framework-2-authentication-acl-using-eventmanager/

First I created an extra config for ACL (could be also in module.config.php, but I prefer to have it in a separated file)


    config/acl.config.php

01    <!--?php
02    return array(
03        'acl' =--> array(
04            'roles' => array(
05                'guest'   => null,
06                'member'  => 'guest'
07            ),
08            'resources' => array(
09                'allow' => array(
10                    'user' => array(
11                        'login' => 'guest',
12                        'all'   => 'member'
13                    )
14                )
15            )
16        )
17    );

Next step is to create the Acl Class where we manage the roles and resources which we have defined in the config

    src/User/Acl/Acl.php

001    <!--?php
002    /**
003     * File for Acl Class
004     *
005     * @category  User
006     * @package   User_Acl
007     * @author    Marco Neumann <webcoder_at_binware_dot_org-->
008     * @copyright Copyright (c) 2011, Marco Neumann
009     * @license   http://binware.org/license/index/type:new-bsd New BSD License
010     */
011    
012    /**
013     * @namespace
014     */
015    namespace User\Acl;
016    
017    /**
018     * @uses Zend\Acl\Acl
019     * @uses Zend\Acl\Role\GenericRole
020     * @uses Zend\Acl\Resource\GenericResource
021     */
022    use Zend\Acl\Acl as ZendAcl,
023        Zend\Acl\Role\GenericRole as Role,
024        Zend\Acl\Resource\GenericResource as Resource;
025    
026    /**
027     * Class to handle Acl
028     *
029     * This class is for loading ACL defined in a config
030     *
031     * @category User
032     * @package  User_Acl
033     * @copyright Copyright (c) 2011, Marco Neumann
034     * @license   http://binware.org/license/index/type:new-bsd New BSD License
035     */
036    class Acl extends ZendAcl {
037        /**
038         * Default Role
039         */
040        const DEFAULT_ROLE = 'guest';
041    
042        /**
043         * Constructor
044         *
045         * @param array $config
046         * @return void
047         * @throws \Exception
048         */
049        public function __construct($config)
050        {
051            if (!isset($config['acl']['roles']) || !isset($config['acl']['resources'])) {
052                throw new \Exception('Invalid ACL Config found');
053            }
054    
055            $roles = $config['acl']['roles'];
056            if (!isset($roles[self::DEFAULT_ROLE])) {
057                $roles[self::DEFAULT_ROLE] = '';
058            }
059    
060            $this->_addRoles($roles)
061                 ->_addResources($config['acl']['resources']);
062        }
063    
064        /**
065         * Adds Roles to ACL
066         *
067         * @param array $roles
068         * @return User\Acl
069         */
070        protected function _addRoles($roles)
071        {
072            foreach ($roles as $name => $parent) {
073                if (!$this->hasRole($name)) {
074                    if (empty($parent)) {
075                        $parent = array();
076                    } else {
077                        $parent = explode(',', $parent);
078                    }
079    
080                    $this->addRole(new Role($name), $parent);
081                }
082            }
083    
084            return $this;
085        }
086    
087        /**
088         * Adds Resources to ACL
089         *
090         * @param $resources
091         * @return User\Acl
092         * @throws \Exception
093         */
094        protected function _addResources($resources)
095        {
096            foreach ($resources as $permission => $controllers) {
097                foreach ($controllers as $controller => $actions) {
098                    if ($controller == 'all') {
099                        $controller = null;
100                    } else {
101                        if (!$this->hasResource($controller)) {
102                            $this->addResource(new Resource($controller));
103                        }
104                    }
105    
106                    foreach ($actions as $action => $role) {
107                        if ($action == 'all') {
108                            $action = null;
109                        }
110    
111                        if ($permission == 'allow') {
112                            $this->allow($role, $controller, $action);
113                        } elseif ($permission == 'deny') {
114                            $this->deny($role, $controller, $action);
115                        } else {
116                            throw new \Exception('No valid permission defined: ' . $permission);
117                        }
118                    }
119                }
120            }
121    
122            return $this;
123        }
124    }

I decided to use a Controller Plugin (zf1 ActionHelpers) for the Authentication interaction

    src/User/Controller/Plugin/UserAuthentication.php

001    <!--?php
002    /**
003     * File for UserAuthentication Class
004     *
005     * @category   User
006     * @package    User_Controller
007     * @subpackage User_Controller_Plugin
008     * @author     Marco Neumann <webcoder_at_binware_dot_org-->
009     * @copyright  Copyright (c) 2011, Marco Neumann
010     * @license    http://binware.org/license/index/type:new-bsd New BSD License
011     */
012    
013    /**
014     * @namespace
015     */
016    namespace User\Controller\Plugin;
017    
018    /**
019     * @uses Zend\Mvc\Controller\Plugin\AbstractPlugin
020     * @uses Zend\Authentication\AuthenticationService
021     * @uses Zend\Authentication\Adapter\DbTable
022     */
023    use Zend\Mvc\Controller\Plugin\AbstractPlugin,
024        Zend\Authentication\AuthenticationService,
025        Zend\Authentication\Adapter\DbTable as AuthAdapter;
026    
027    /**
028     * Class for User Authentication
029     *
030     * Handles Auth Adapter and Auth Service to check Identity
031     *
032     * @category   User
033     * @package    User_Controller
034     * @subpackage User_Controller_Plugin
035     * @copyright  Copyright (c) 2011, Marco Neumann
036     * @license    http://binware.org/license/index/type:new-bsd New BSD License
037     */
038    class UserAuthentication extends AbstractPlugin
039    {
040        /**
041         * @var AuthAdapter
042         */
043        protected $_authAdapter = null;
044    
045        /**
046         * @var AuthenticationService
047         */
048        protected $_authService = null;
049    
050        /**
051         * Check if Identity is present
052         *
053         * @return bool
054         */
055        public function hasIdentity()
056        {
057            return $this->getAuthService()->hasIdentity();
058        }
059    
060        /**
061         * Return current Identity
062         *
063         * @return mixed|null
064         */
065        public function getIdentity()
066        {
067            return $this->getAuthService()->getIdentity();
068        }
069    
070        /**
071         * Sets Auth Adapter
072         *
073         * @param \Zend\Authentication\Adapter\DbTable $authAdapter
074         * @return UserAuthentication
075         */
076        public function setAuthAdapter(AuthAdapter $authAdapter)
077        {
078            $this->_authAdapter = $authAdapter;
079    
080            return $this;
081        }
082    
083        /**
084         * Returns Auth Adapter
085         *
086         * @return \Zend\Authentication\Adapter\DbTable
087         */
088        public function getAuthAdapter()
089        {
090            if ($this->_authAdapter === null) {
091                $this->setAuthAdapter(new AuthAdapter());
092            }
093    
094            return $this->_authAdapter;
095        }
096    
097        /**
098         * Sets Auth Service
099         *
100         * @param \Zend\Authentication\AuthenticationService $authService
101         * @return UserAuthentication
102         */
103        public function setAuthService(AuthenticationService $authService)
104        {
105            $this->_authService = $authService;
106    
107            return $this;
108        }
109    
110        /**
111         * Gets Auth Service
112         *
113         * @return \Zend\Authentication\AuthenticationService
114         */
115        public function getAuthService()
116        {
117            if ($this->_authService === null) {
118                $this->setAuthService(new AuthenticationService());
119            }
120    
121            return $this->_authService;
122        }
123    
124    }

Now we can create the Event Handler were we will implement the AuthenticationPlugin (at this point, I think that using a Controller Plugin is not the right way to do it, but for now I will leave it so until I have a better solution…) and the Acl

    src/Event/Authentication.php

001    <!--?php
002    /**
003     * File for Event Class
004     *
005     * @category  User
006     * @package   User_Event
007     * @author    Marco Neumann <webcoder_at_binware_dot_org-->
008     * @copyright Copyright (c) 2011, Marco Neumann
009     * @license   http://binware.org/license/index/type:new-bsd New BSD License
010     */
011    
012    /**
013     * @namespace
014     */
015    namespace User\Event;
016    
017    /**
018     * @uses Zend\Mvc\MvcEvent
019     * @uses User\Controller\Plugin\UserAuthentication
020     * @uses User\Acl\Acl
021     */
022    use Zend\Mvc\MvcEvent as MvcEvent,
023        User\Controller\Plugin\UserAuthentication as AuthPlugin,
024        User\Acl\Acl as AclClass;
025    
026    /**
027     * Authentication Event Handler Class
028     *
029     * This Event Handles Authentication
030     *
031     * @category  User
032     * @package   User_Event
033     * @copyright Copyright (c) 2011, Marco Neumann
034     * @license   http://binware.org/license/index/type:new-bsd New BSD License
035     */
036    class Authentication
037    {
038        /**
039         * @var AuthPlugin
040         */
041        protected $_userAuth = null;
042    
043        /**
044         * @var AclClass
045         */
046        protected $_aclClass = null;
047    
048        /**
049         * preDispatch Event Handler
050         *
051         * @param \Zend\Mvc\MvcEvent $event
052         * @throws \Exception
053         */
054        public function preDispatch(MvcEvent $event)
055        {
056            //@todo - Should we really use here and Controller Plugin?
057            $userAuth = $this->getUserAuthenticationPlugin();
058            $acl = $this->getAclClass();
059            $role = AclClass::DEFAULT_ROLE;
060    
061            if ($userAuth->hasIdentity()) {
062                $user = $userAuth->getIdentity();
063                $role = 'member'; //@todo - Get role from user!
064            }
065    
066    
067            $routeMatch = $event->getRouteMatch();
068            $controller = $routeMatch->getParam('controller');
069            $action     = $routeMatch->getParam('action');
070    
071            if (!$acl->hasResource($controller)) {
072                throw new \Exception('Resource ' . $controller . ' not defined');
073            }
074    
075            if (!$acl->isAllowed($role, $controller, $action)) {
076                $url = $event->getRouter()->assemble(array(), array('name' => 'login'));
077                $response = $event->getResponse();
078                $response->headers()->addHeaderLine('Location', $url);
079                $response->setStatusCode(302);
080                $response->sendHeaders();
081                exit;
082            }
083        }
084    
085        /**
086         * Sets Authentication Plugin
087         *
088         * @param \User\Controller\Plugin\UserAuthentication $userAuthenticationPlugin
089         * @return Authentication
090         */
091        public function setUserAuthenticationPlugin(AuthPlugin $userAuthenticationPlugin)
092        {
093            $this->_userAuth = $userAuthenticationPlugin;
094    
095            return $this;
096        }
097    
098        /**
099         * Gets Authentication Plugin
100         *
101         * @return \User\Controller\Plugin\UserAuthentication
102         */
103        public function getUserAuthenticationPlugin()
104        {
105            if ($this->_userAuth === null) {
106                $this->_userAuth = new AuthPlugin();
107            }
108    
109            return $this->_userAuth;
110        }
111    
112        /**
113         * Sets ACL Class
114         *
115         * @param \User\Acl\Acl $aclClass
116         * @return Authentication
117         */
118        public function setAclClass(AclClass $aclClass)
119        {
120            $this->_aclClass = $aclClass;
121    
122            return $this;
123        }
124    
125        /**
126         * Gets ACL Class
127         *
128         * @return \User\Acl\Acl
129         */
130        public function getAclClass()
131        {
132            if ($this->_aclClass === null) {
133                $this->_aclClass = new AclClass(array());
134            }
135    
136            return $this->_aclClass;
137        }
138    }

Now we need to attach the Event Handler to the EventManager, this will be done in the Module Class (haven’t found a better way to do it). I also had to attach an own function and from there trigger the User\Event\Authentication function (not very elegant ;( )

    Module.php

01    <!--?php
02    /**
03     * File for Module Class
04     *
05     * @category  User
06     * @package   User
07     * @author    Marco Neumann <webcoder_at_binware_dot_org-->
08     * @copyright Copyright (c) 2011, Marco Neumann
09     * @license   http://binware.org/license/index/type:new-bsd New BSD License
10     */
11    
12    /**
13     * @namespace
14     */
15    namespace User;
16    
17    /**
18     * @uses Zend\Module\Consumer\AutoloaderProvider
19     * @uses Zend\EventManager\StaticEventManager
20     */
21    use Zend\Module\Consumer\AutoloaderProvider,
22        Zend\EventManager\StaticEventManager;
23    
24    /**
25     * Module Class
26     *
27     * Handles Module Initialization
28     *
29     * @category  User
30     * @package   User
31     * @copyright Copyright (c) 2011, Marco Neumann
32     * @license   http://binware.org/license/index/type:new-bsd New BSD License
33     */
34    class Module implements AutoloaderProvider
35    {
36        /**
37         * Init function
38         *
39         * @return void
40         */
41        public function init()
42        {
43            // Attach Event to EventManager
44            $events = StaticEventManager::getInstance();
45            $events->attach('Zend\Mvc\Controller\ActionController', 'dispatch', array($this, 'mvcPreDispatch'), 100); //@todo - Go directly to User\Event\Authentication
46        }
47    
48        /**
49         * Get Autoloader Configuration
50         *
51         * @return array
52         */
53        public function getAutoloaderConfig()
54        {
55            return array(
56                'Zend\Loader\ClassMapAutoloader' => array(
57                    __DIR__ . '/autoload_classmap.php'
58                ),
59                'Zend\Loader\StandardAutoloader' => array(
60                    'namespaces' => array(
61                        __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__
62                    )
63                )
64            );
65        }
66    
67        /**
68         * Get Module Configuration
69         *
70         * @return array
71         */
72        public function getConfig()
73        {
74            return include __DIR__ . '/config/module.config.php';
75        }
76    
77        /**
78         * MVC preDispatch Event
79         *
80         * @param $event
81         * @return mixed
82         */
83        public function mvcPreDispatch($event) {
84            $di = $event->getTarget()->getLocator();
85            $auth = $di->get('User\Event\Authentication');
86    
87            return $auth->preDispatch($event);
88        }
89    }

Here is the config where we attach all needed classes and load acl.config.php

    config/module.config.php

01    <!--?php
02    return array(
03        'di' =--> array(
04            'instance' => array(
05                'alias' => array(
06                    'user' => 'User\Controller\UserController'
07                ),
08                'user' => array(
09                    'parameters' => array(
10                        'broker' => 'Zend\Mvc\Controller\PluginBroker'
11                    )
12                ),
13                'User\Event\Authentication' => array(
14                    'parameters' => array(
15                        'userAuthenticationPlugin' => 'User\Controller\Plugin\UserAuthentication',
16                        'aclClass'                 => 'User\Acl\Acl'
17                    )
18                ),
19                'User\Acl\Acl' => array(
20                    'parameters' => array(
21                        'config' => include __DIR__ . '/acl.config.php'
22                    )
23                ),
24                'User\Controller\Plugin\UserAuthentication' => array(
25                    'parameters' => array(
26                        'authAdapter' => 'Zend\Authentication\Adapter\DbTable'
27                    )
28                ),
29                'Zend\Authentication\Adapter\DbTable' => array(
30                    'parameters' => array(
31                        'zendDb' => 'Zend\Db\Adapter\Mysqli',
32                        'tableName' => 'users',
33                        'identityColumn' => 'email',
34                        'credentialColumn' => 'password',
35                        'credentialTreatment' => 'SHA1(CONCAT(?, "secretKey"))'
36                    )
37                ),
38                'Zend\Db\Adapter\Mysqli' => array(
39                    'parameters' => array(
40                        'config' => array(
41                            'host' => 'localhost',
42                            'username' => 'username',
43                            'password' => 'password',
44                            'dbname' => 'dbname',
45                            'charset' => 'utf-8'
46                        )
47                    )
48                ),
49                'Zend\Mvc\Controller\PluginLoader' => array(
50                    'parameters' => array(
51                        'map' => array(
52                            'userAuthentication' => 'User\Controller\Plugin\UserAuthentication'
53                        )
54                    )
55                ),
56                'Zend\View\PhpRenderer' => array(
57                    'parameters' => array(
58                        'options' => array(
59                            'script_paths' => array(
60                                'user' => __DIR__ . '/../views'
61                            )
62                        )
63                    )
64                )
65            )
66        ),
67        'routes' => array(
68            'login' => array(
69                'type' => 'Zend\Mvc\Router\Http\Literal',
70                'options' => array(
71                    'route'    => '/login',
72                    'defaults' => array(
73                        'controller' => 'user',
74                        'action'     => 'login',
75                    )
76                )
77            )
78        )
79    );

Well, we are now done, we only need to create the Login Form and the Controller

    src/Form/Login.php

01    <!--?php
02    /**
03     * File for Login Form Class
04     *
05     * @category  User
06     * @package   User_Form
07     * @author    Marco Neumann <webcoder_at_binware_dot_org-->
08     * @copyright Copyright (c) 2011, Marco Neumann
09     * @license   http://binware.org/license/index/type:new-bsd New BSD License
10     */
11    
12    /**
13     * @namespace
14     */
15    namespace User\Form;
16    
17    /**
18     * @uses Zend\Form\Form
19     */
20    use Zend\Form\Form;
21    
22    /**
23     * Login Form Class
24     *
25     * Login Form
26     *
27     * @category  User
28     * @package   User_Form
29     * @copyright Copyright (c) 2011, Marco Neumann
30     * @license   http://binware.org/license/index/type:new-bsd New BSD License
31     */
32    class Login extends Form
33    {
34        /**
35         * Initialize Form
36         */
37        public function init()
38        {
39            $this->setMethod('post')
40                 ->loadDefaultDecorators()
41                 ->addDecorator('FormErrors');
42    
43            $this->addElement(
44                'text',
45                'username',
46                array(
47                     'filters' => array(
48                         array('StringTrim')
49                     ),
50                     'validators' => array(
51                         'EmailAddress'
52                     ),
53                     'required' => true,
54                     'label'    => 'Email'
55                )
56            );
57    
58            $this->addElement(
59                'password',
60                'password',
61                array(
62                     'filters' => array(
63                         array('StringTrim')
64                     ),
65                     'validators' => array(
66                         array(
67                             'StringLength',
68                             true,
69                             array(
70                                 6,
71                                 999
72                             )
73                         )
74                     ),
75                     'required' => true,
76                     'label'    => 'Password'
77                )
78            );
79    
80            $this->addElement(
81                'hash',
82                'csrf',
83                array(
84                     'ignore' => true,
85                     'decorators' => array('ViewHelper')
86                )
87            );
88    
89            $this->addElement(
90                'submit',
91                'login',
92                array(
93                     'ignore' => true,
94                     'label' => 'Login'
95                )
96            );
97    
98        }
99    }

    src/User/Controller/UserController.php

01    <!--?php
02    /**
03     * File for User Controller Class
04     *
05     * @category  User
06     * @package   User_Controller
07     * @author    Marco Neumann <webcoder_at_binware_dot_org-->
08     * @copyright Copyright (c) 2011, Marco Neumann
09     * @license   http://binware.org/license/index/type:new-bsd New BSD License
10     */
11    
12    /**
13     * @namespace
14     */
15    namespace User\Controller;
16    
17    /**
18     * @uses Zend\Mvc\Controller\ActionController
19     * @uses User\Form\Login
20     */
21    use Zend\Mvc\Controller\ActionController,
22        User\Form\Login as LoginForm;
23    
24    /**
25     * User Controller Class
26     *
27     * User Controller
28     *
29     * @category  User
30     * @package   User_Controller
31     * @copyright Copyright (c) 2011, Marco Neumann
32     * @license   http://binware.org/license/index/type:new-bsd New BSD License
33     */
34    class UserController extends ActionController
35    {
36        /**
37         * Index Action
38         */
39        public function indexAction()
40        {
41            //@todo - Implement indexAction
42        }
43    
44        /**
45         * Login Action
46         *
47         * @return array
48         */
49        public function loginAction()
50        {
51            $form = new LoginForm();
52            $request = $this->getRequest();
53    
54            if ($request->isPost() && $form->isValid($request->post()->toArray())) {
55                $uAuth = $this->getLocator()->get('User\Controller\Plugin\UserAuthentication'); //@todo - We must use PluginLoader $this->userAuthentication()!!
56                $authAdapter = $uAuth->getAuthAdapter();
57    
58                $authAdapter->setIdentity($form->getValue('username'));
59                $authAdapter->setCredential($form->getValue('password'));
60    
61                \Zend\Debug::dump($uAuth->getAuthService()->authenticate($authAdapter));
62            }
63    
64            return array('loginForm' => $form);
65        }
66    
67        /**
68         * Logout Action
69         */
70        public function logoutAction()
71        {
72            $this->getLocator()->get('User\Controller\Plugin\UserAuthentication')->clearIdentity(); //@todo - We must use PluginLoader $this->userAuthentication()!!
73        }

74    }



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值