我想将未经身份验证的用户(访客)转发到登录表单。
使用重定向时,我需要将访客用户从他们正在寻找的页面重定向到登录页面;然后再将它们重新定向。
示例:
(访客访问)mySite / controller / action?var1 = xxx& var2 = yyy
(AclService重定向)mySite / login
(AuthService重定向)mySite / controller / action?var1 = xxx& var2 = yyy
所有这一切只能使用会话变量(我猜)。
我的想法是将用户转发到mySite / login。验证成功后,我唯一需要做的就是重定向到当前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 :(得分:0)
回答我自己的问题:
不,这没有任何意义。那是因为
转发是一种在另一个控制器上发送控制器的模式 控制器已经发送 (Forward to another controller/action from module.php)
因此,acl检查部分无用,因为放入受保护页面的任何内容都将在转发之前执行。 这意味着如果我有一个仅为经过身份验证的用户设计的用户页面(控制器),我会调用类似的函数:
$name=$this->getUserName($userId);
我将收到一条错误消息,因为在验证过程中应该设置var $ userId。等等...
无论如何,我找到了一个更好的解决方案,行为完全不同,但结果相同(显然没有上述问题)。
然而,由于我原来的问题非常具体,为了清楚起见,我想更好地解释前缀目标:
我有一个在调度之前运行的acl脚本,如果用户未经过身份验证(role = guest),则会将用户重定向到登录表单。
当用户通过登录表单发送凭据并进行身份验证时,我希望根据他们到达表单的方式执行动态重定向。
动态重定向应遵循以下条件:
当用户通过www.site.com/login访问表单时,经过身份验证后,应将其重定向到www.site.com/user_home
当用户通过www.site.com/controller/action/param?var=xxx&var2=yyy [...]访问表单时,经过身份验证后,应将其重定向到相同的网址,而不会丢失任何内容参数。
用户通过身份验证后,无法访问www.site.com/login页面(因为没用)。这意味着寻找此页面的用户应该被重定向到其他地方。
但我也是从“重定向不好”的假设开始的:
如果没有直接联系到,浏览器历史记录中不应有任何www.site.com/login的痕迹。 这是因为浏览器的后退按钮可能会搞砸第2点所说的任何内容(冲突)。例如:
我发现实现这一目标的解决方案是使用重定向插件以及与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
->...
guest虚拟机模块中的任何内容都应该可供public(role = guest)访问,但不能访问已经过身份验证的用户(根据上面的第3点)。
最后,代码:
路径: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'));
}
[...]
}
路径: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;
}
[...]
}
路径: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。:希望我的英语结果可读。 : - )