代码之家  ›  专栏  ›  技术社区  ›  Gwen Hufschmid

zf2 acl转发到登录表单

  •  0
  • Gwen Hufschmid  · 技术社区  · 9 年前

    我想将未经身份验证的用户(访客)转发到登录表单。

    当使用重定向时,我需要将访客用户从他们要查找的页面重定向到登录页面;然后再次重定向它们。

    例子:

    (AclService重定向)mySite/login

    (AuthService重定向)mySite/controller/action?var1=xxx&var2=yyy

    所有这些都只能(我想)使用会话变量。

    这种行为的优点是,如果用户单击浏览器的后退按钮,页面将保持不变(mySite/controller/action?var1=xxx&var2=yyy)。

    这是我的代码:

    在模块中。php

    public function onBootstrap(MvcEvent $e){
    
    $app = $e->getApplication();
    $sm  = $app->getServiceManager();
    $acl = $sm->get('AclService');
    $e -> getApplication()-> getEventManager()->getSharedManager()->attach('Zend\Mvc\Controller\AbstractActionController',MvcEvent::EVENT_DISPATCH,array($acl, 'checkAcl'),-10);
    
    }
    

    [...]
    
    if (!$this->acl ->isAllowed($role, $controller, $action)){
    
       //when my AuthService->hasIdentity() returns false, the the role is guest
       if($role=='guest'){ 
          $controllerClass = get_class($e->getTarget());
             //this prevents nested forwards
             if($controllerClass!='Auth\Controller\Auth2Controller'){
             $e->setResult($e->getTarget()->forward()->dispatch('Auth\Controller\Auth2',array('action'=>'index')));
              }
    
        }
        else{...}
    }
    

    然后在AuthService中,我使用这个函数(在mysite/login中调用)重定向经过身份验证的用户

    //if the login page has ben forwarded
    if($e->getRouteMatch()->getParam('controller')!='Auth\Controller\Auth2'
    {
    $url=$this->Config['webhost'].$e->getRequest()->getRequestUri();
    return $e->getTarget()->redirect()->toUrl($url);
    }
    //if the request comes directly from a login/register attempt
    else{return $e->getTarget()->redirect()->toRoute('user_home');}
    

    你知道更好的方法吗?

    1 回复  |  直到 9 年前
        1
  •  0
  •   Gwen Hufschmid    9 年前

    回答我自己的问题:

    不,这毫无意义。那是因为

    转发是在另一个控制器发生故障时调度控制器的一种模式 控制器已调度 Forward to another controller/action from module.php )

    这意味着,如果我有一个仅为经过身份验证的用户设计的用户页面(控制器),并且我调用了如下函数:

    $name=$this->getUserName($userId);
    


    无论如何,我找到了一个更好的解决方案,具有完全不同的行为,但结果相同(显然没有上述问题)。

    然而,由于我最初的问题非常具体,为了清楚起见,我想更好地解释 :

    我得到了一个acl脚本,该脚本在Dispatch之前运行,如果用户没有经过身份验证,它会将用户重定向到登录表单(role=guest)。

    .

    1. 当用户通过www.site访问表单时。com/login,一旦通过身份验证,它们应该被重定向到www.site。com/user_主页

    2. 一旦用户通过身份验证,他们就不能访问www.site页面。com/login(因为没有用)。这意味着搜索此页面的用户应该被重定向到其他地方。

    但我也从假设开始

    1. 如果没有直接联系到,就不应该有任何www.site的痕迹。com/登录到浏览器历史记录。

      • 我到达页面站点。com/user/post/2016?tag=foo,但我未登录或会话已过期
      • 但是,如果我通过浏览器的按钮返回,那么我请求的来源是www.site。com/登录,如第1点和第3点所定义, 我将被重定向到www.site。com/user_home失去返回站点的能力。com/user/post/2016?标记=foo(如果不是通过历史记录)。(这就是我尝试使用转发插件的原因)

    我发现实现这一目标的解决方案是,除了使用自己动手转发过程外,还使用重定向插件,该过程与MVC的Routemach一起工作。

    https://samsonasik.wordpress.com/2013/05/29/zend-framework-2-working-with-authenticationservice-and-db-session-save-handler/

    与samsonasik代码的主要区别在于,我添加了一个名为authService的服务,该服务单独处理与身份验证相关的函数。 这只是为了使代码更具可读性/可重用性,因为我需要在身份验证时执行一些自定义逻辑(与我的应用程序设计相关)。

    这里是我的结构的主要部分:

    Application
    Auth
        ->service
                 ->authService
                 ->aclService
    Guest
         ->Controller
                     ->guestHomeController
                                          ->loginAction
                                          ->singUpAction
                                          ->...
                     ->...
    User
        ->Controller
                    ->userHomeController
                    ->...
    

    最后,代码:

    namespace Auth;
    
    use Zend\Mvc\MvcEvent;
    
    class Module
    {
    
      public function onBootstrap(MvcEvent $e)
      {
        $app = $e->getApplication();
        $sm  = $app->getServiceManager();
    
        $acl = $sm->get('aclService');
    
        $acl->initAcl();
        $e -> getApplication() -> getEventManager() -> attach(MvcEvent::EVENT_ROUTE, array($acl, 'checkAcl'));
      }
    
      [...]
    }
    

    路径:Auth/src/Auth/Service/AclService。php

    namespace Auth\Service;
    
    use Zend\Permissions\Acl\Acl;
    use Zend\Permissions\Acl\Role\GenericRole as Role;
    use Zend\Permissions\Acl\Resource\GenericResource as Resource;
    use Zend\Mvc\MvcEvent;
    
    
    class AclService  {
    
    protected $authService;
    protected $config;
    protected $acl;
    protected $role;
    
    
        public function __construct($authService,$config)
        {
            if(!$this->acl){$this->acl=new Acl();}
            $this->authService = $authService;
            $this->config = $config;
        }
    
    
        public function initAcl()
        {
           $this->acl->addRole(new Role('guest'));
           [...]
    
           $this->acl->addResource(new Resource('Guest\Controller\GuestHome'));
           [...]
    
           $this->acl->allow('role', 'controller','action');
           [...]
        }
    
    
       public function checkAcl(MvcEvent $e)
        {
          $controller=$e -> getRouteMatch()->getParam('controller');
          $action=$e -> getRouteMatch()->getParam('action');
          $role=$this->getRole();
    
          if (!$this->acl ->isAllowed($role, $controller, $action)){
    
            //if user isn't authenticated...
            if($role=='guest'){
              //set current route controller and action (this doesn't modify the url, it's non a redirect)
              $e -> getRouteMatch()->setParam('controller', 'Guest\Controller\GuestHome');
              $e -> getRouteMatch()->setParam('action', 'login');
            }//if
    
            //if user is authenticated but has not the permission...
            else{
              $response = $e -> getResponse();
              $response -> getHeaders() -> addHeaderLine('Location', $e -> getRequest() -> getBaseUrl() . '/404');
              $response -> setStatusCode(404);
            }//else
          }//if
        }
    
       public function getRole()
       {
       if($this->authService->hasIdentity()){
       [...]
       }
       else{$role='guest';}
       return $role;
       }
    
       [...]
    
    }
    

    namespace Guest\Controller;
    
    use Zend\Mvc\Controller\AbstractActionController;
    use Zend\View\Model\ViewModel;
    use Zend\Form\Factory;
    
    class GuestHomeController extends AbstractActionController
    {
    
        protected $authService;
        protected $config;
        protected $routeName;
    
        public function __construct($authService, $config, $routeMatch)
        {
            $this->authService = $authService;
            $this->config = $config;
            $this->routeName = $routeMatch->getMatchedRouteName();
        }
    
    
        public function loginAction()
        {
    
          $forwardMessage=null;
    
          //When users DOESN'T reach the form via www.site.com/login (they get forwarded), set a message to tell them what's going on
          if($this->routeName!='login'){
            $forwardMessage='You must be logged in to see this page!!!';
          }
    
          //This could probably be moved elsewhere and be triggered (when module is "Guest") on dispatch event with maximum priority (predispatch)
          if ($this->authService->hasIdentity()) {
            $this->dynamicRedirect();
          }
    
          $factory = new Factory();
          $form = $factory->createForm($this->config['LoginForm']);
    
          $request=$this->getRequest();
    
          if ($request->isPost()) {
    
            $form->setData($request->getPost());
    
            if ($form->isValid()) {
    
              $dataform = $form->getData();
              $result=$this->authService->authenticate($dataform);
    
              //result=status code
              if($result===1){$this->dynamicRedirect();}
              else{...}
            }//$form->isValid()
          }//$request->isPost()
    
    
          $viewModel = new ViewModel();
          $viewModel->setVariable('form', $form);
          $viewModel->setVariable('error', $forwardMessage);
    
          return $viewModel;
        }
    
    
        public function dynamicRedirect()
        {
          //if the form has been forwarded
          if($this->routeName!='login'){
            $url=$this->config['webhost'].$this->getRequest()->getRequestUri();
            return $this->redirect()->toUrl($url);
          }
          else{return $this->redirect()->toRoute('userHome');}//else
        }
    
        [...]
    }
    

    如果我发现其他问题,我会更新这篇文章,但现在它很有魅力。

    推荐文章