2017-09-09 14 views
0

Je souhaite transférer des utilisateurs non authentifiés (invités) vers un formulaire de connexion. Lorsque je travaille avec la redirection, je dois rediriger les utilisateurs invités de la page qu'ils recherchent vers la page de connexion; puis les rediriger à nouveau.zf2 acl transmettre au formulaire de connexion

Exemple:

(visites des clients) mySite/contrôleur/action var1 = xxx & var2 = yyy

(AclService redirige) mySite/connexion

(AuthService redirige) mySite/contrôleur/action? var1 = xxx & var2 = yyy

Et tout cela ne peut fonctionner (je suppose) en utilisant des variables de session.

Mon idée est plutôt de rediriger l'utilisateur vers mySite/login. Lorsque l'authentification est réussie, la seule chose que je dois faire est de rediriger vers l'URL actuelle. L'avantage de ce comportement est que si l'utilisateur clique sur le bouton de retour du navigateur, la page reste la même (mySite/controller/action? Var1 = xxx & var2 = yyy).

Voici mon code:

dans 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); 

} 

dans mon AclService, la fonction 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{...} 
} 

Et puis dans mon AuthService, j'utiliser cette fonction (appelée dans monsite/login) pour rediriger les utilisateurs authentifiés

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

Qu'en pensez-vous? Ca a du sens?

Connaissez-vous une meilleure approche?

+0

Je suggère de ne pas rediriger, mais montrer un formulaire de connexion tout de suite. – akond

+0

Salut akond, que voulez-vous dire? Mon approche est de vérifier acl sur l'événement d'expédition et si l'utilisateur n'est pas authentifié à FORWARD/DISPATCH la demande au formulaire de connexion Contrôleur/action. J'utilise la fonction Redirection uniquement lorsque l'utilisateur s'authentifie avec succès. Comment puis-je afficher un formulaire de connexion lors de l'envoi? Je vous remercie –

Répondre

0

pour répondre à ma propre question:

Non, cela n'a aucun sens. En effet,

Forwarding est un modèle d'envoyer un contrôleur quand un autre contrôleur a déjà été expédié (Forward to another controller/action from module.php)

Par conséquent, le contrôle de acl est partiellement inutile parce que tout placé dans une page protégée sera être exécuté avant l'expédition. Cela signifie que si j'ai une page d'utilisateur (contrôleur) conçu pour les utilisateurs authentifiés et j'appeler une fonction comme:

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

Je vais obtenir un message d'erreur car le var userId $ est censé être setted au cours de la processus d'authentification. Etc...


Quoi qu'il en soit, j'ai trouvé une meilleure solution avec un comportement complètement différent, mais le même résultat (évidemment sans le problème décrit ci-dessus).

Cependant, depuis ma première question était très spécifique, par souci de clarté, je voudrais mieux expliquer l'objectif préfixé:

Je suis un script acl qui fonctionne avant dispathcing et redirige l'utilisateur vers un formulaire de connexion s'ils ne sont pas authentifiés (rôle = invité).

Lorsque les utilisateurs envoient leurs informations d'identification via le formulaire de connexion et qu'ils sont authentifiés, je souhaite effectuer une redirection dynamique en fonction de la manière dont ils ont atteint le formulaire.

La dynamique redirect devrait suivre ce type de problèmes:

  1. Lorsque les utilisateurs atteignent le formulaire via www.site.com/login, une fois authentifiées, ils devraient être redirigés vers www.site.com/user_home~~V~~3rd

  2. Lorsque les utilisateurs accèdent au formulaire via www.site.com/controller/action/param?var=xxx & var2 = yyy [...], une fois authentifiés, ils doivent être redirigés vers le même URL sans perdre aucun paramètre. Une fois que les utilisateurs sont authentifiés, ils ne devraient pas pouvoir accéder à la page www.site.com/login (car elle est inutile). Cela signifie que les utilisateurs recherchant cette page devraient être redirigés ailleurs.

Mais j'ai aussi commencé à partir de l'hypothèse que "redirect est mauvais":

  1. Si pas atteint directement, il ne devrait pas y avoir de trace de www .site.com/connectez-vous dans l'historique du navigateur. Cela parce que le bouton de retour du navigateur pourrait bousiller tout ce qui est dit au point 2 (conflit). Exemple:

    • J'atteint la page site.com/user/post/2016?tag=foo mais je ne suis pas connecté ou session a expiré
    • Je redirigés vers www.site.com/ connexion où je remplis le formulaire d'authentification et le soumets
    • Une fois authentifié, je suis redirigé à nouveau à site.com/user/post/2016?tag=foo
    • MAIS, si je reviens par le bouton du navigateur, alors l'origine de ma demande est www.site.com/login et, tel que défini aux points 1 et 3, je serai redirigé vers www.site.com/user_home sans la possibilité de retourner sur site.com/user/post/2016? Tag = foo (si non vi Une histoire). (Ce qui est la raison pour laquelle je voulais travailler avec le plug-in en avant)

La solution que je trouve pour atteindre cet objectif est d'utiliser le plug-in de redirection en plus d'un do-it-yourself Forwarding processus qui fonctionne avec le Routemach du MVC.

je commencé à coder suivant le tutoriel de cette samsonasik: https://samsonasik.wordpress.com/2013/05/29/zend-framework-2-working-with-authenticationservice-and-db-session-save-handler/

La principale différence à partir du code de samsonasik est que j'ai ajouté un service appelé authService qui gère les fonctions liées à l'authentification séparément. Simplement pour rendre le code plus lisible/réutilisable car j'ai besoin d'une logique personnalisée (liée à ma conception d'application) pour être exécutée lors de l'authentification.

Voici les principales sections de ma structure:

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

Tout l'intérieur du module invité est censé être accessible au public (rôle = guest) mais pas aux utilisateurs déjà authentifiés (conformément au point 3 ci-dessus).

Et enfin, le code:

chemin

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

    [...] 
} 
chemin

: 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; 
    } 

    [...] 

} 
chemin

: Guest/src/Guest/Contrôleur/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 
    } 

    [...] 
} 

Je vais mettre à jour ce post si je trouve d'autres problèmes mais pour l'instant cela fonctionne comme un charme.

P.S .: J'espère que mes résultats en anglais sont lisibles. :-)