2017-09-09 31 views
0

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

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

实施例:

(客体的访问次数)MYSITE /控制器/动作VAR1 = XXX & VAR2 = YYY

(AclService重定向)MYSITE /登录

(AuthService重定向)MYSITE /控制器/ action?var1 = xxx & var2 = yyy

而这一切只能使用会话变量(我猜)。

我的想法是将用户转发到mySite /登录。当身份验证成功时,我需要做的唯一事情就是重定向到当前的URL。 此行为的优点是,如果用户单击浏览器的后退按钮,页面保持不变(mySite/controller/action?var1 = xxx & var2 = yyy)。

这里我的代码:

在module.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); 

} 
在我AclService

,checkAcl功能

[...] 

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');} 

您对此有何看法?这说得通?

你知道更好的方法吗?

+0

我建议不要重定向,但立即显示登录表单。 – akond

+0

嗨,你是什么意思?我的方法是检查acl的调度事件,如果用户未通过身份验证以向登录表单Controller/action发送/发送请求。我只有在用户成功执行时才使用重定向功能。我如何在派送上显示登录表单?谢谢 –

回答

0

回答我自己的问题:

不,它没有任何意义。这是因为

转发是派遣一个控制器模式当另一 控制器已经派出 (Forward to another controller/action from module.php

因此,ACL检查部分是无用的,因为任何东西放入一个受保护的页面会在转发之前执行。 这意味着,如果我有一个用户页面(控制器)设计仅用于身份验证的用户和我打电话的功能等:

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

因为变量$用户id应该是我会得到一个错误消息,在被设置好的认证过程。等等...


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

然而,因为我原来的问题是非常具体的,为了清楚起见,我想解释更好的前缀目标

我得到了dispathcing之前运行,并将用户重定向到ACL脚本一个登录表单,如果他们没有通过身份验证(角色=客人)。

当用户通过登录表单发送凭证并获得身份验证时,我想执行动态重定向,具体取决于他们如何到达表单

动态重定向应遵循theese条件:

  1. 当用户达到通过www.site.com/login形式,一旦被认证,他们应该被重定向到www.site.com/user_home

  2. 当用户通过www.site.com/controller/action/param?var=xxx & var2 = yyy [...]到达表单时,一旦通过验证,它们应该被重定向到相同的URL,而不会丢失任何参数。

  3. 一旦用户通过身份验证,他们应该无法访问www.site.com/login页面(因为没用)。这意味着用户在查找此页面时应该将其重定向到其他地方。

但我也从假设“重定向是坏”开始:

  • 如果不能直接到达,不应该有WWW的任何踪迹.site.com /登录到浏览器历史记录。 这是因为浏览器的后退按钮可能导致点2(冲突)中的任何内容出现乱码。例如:

    • 我到达的页面site.com/user/post/2016?tag=foo但我没有登录或会话已过期
    • 接着,我会重定向到www.site.com/登录我填写验证表格并提交
    • 验证通过后,我再次重定向到site.com/user/post/2016?tag=foo
    • 但是,如果我通过浏览器的按钮返回,那么我的请求的来源是www.site.com/login,并按照第1和第3点中的定义, 我将被重定向到www.site.com/user_home,从而丧失返回site.com/user/post的能力/ 2016?tag = foo(如果不是vi历史)。 (这就是为什么我试图与正向插件的原因)
  • 我发现要实现这个目标的解决方案除了使用重定向插件做它自己的转发过程与MVC的Routemach一起工作。

    我开始编码下面这个samsonasik的教程: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 
           ->... 
    

    来宾模块中的任何内容被认为是访问公共的(角色=来宾)而不是(根据上面第3点)已通过验证的用户。

    最后,代码:

    路径:认证/ Module.php

    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')); 
        } 
    
        [...] 
    } 
    

    路径:认证/ SRC /认证/服务/ 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; 
        } 
    
        [...] 
    
    } 
    

    路径: Guest/src/Guest/Controller/GuestHomeController.php

    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 
        } 
    
        [...] 
    } 
    

    我会更新这篇文章,如果我发现一些其他问题,但现在它像一个魅力。

    P.S .:希望我的英文结果可读。 :-)