Переадресация zf2 acl в форму авторизации

Я хотел бы переслать не авторизованных пользователей (гостя) в форму входа.

При работе с перенаправлением мне нужно перенаправить гостевых пользователей со страницы, которую они ищут, на страницу входа; а затем перенаправить их снова.

Пример:

(гостевые посещения) mySite / controller / action? var1 = xxx&var2 = YYY

(AclService перенаправляет) mySite / login

(AuthService перенаправляет) mySite / controller / action? Var1 = xxx&var2 = YYY

И все это может работать только (я полагаю), используя переменные сеанса.

Моя идея вместо этого, чтобы перенаправить пользователя на мой сайт / логин. Когда аутентификация успешна, единственное, что мне нужно сделать, это перенаправить на текущий 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

Решение

ответить на мой собственный вопрос:

Нет, это не имеет смысла. Это потому что

Пересылка — это шаблон для отправки контроллера, когда другой
диспетчер уже отправлен
(Переадресация на другой контроллер / действие из module.php)

Поэтому проверка acl частично бесполезна, поскольку все, что помещено на защищенную страницу, будет выполнено до пересылки.
Это означает, что если у меня есть пользовательская страница (контроллер), предназначенная только для аутентифицированных пользователей, и я вызываю такую ​​функцию:

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

Я получу сообщение об ошибке, потому что переменная $ userId должна быть установлена ​​в процессе аутентификации. И так далее…


Во всяком случае, я нашел лучшее решение с совершенно другим поведением, но с тем же результатом (очевидно, без проблемы, описанной выше).

Однако, поскольку мой первоначальный вопрос был очень конкретным, для ясности я хотел бы объяснить лучше цель с префиксом:

Я получил сценарий acl, который запускается перед отправкой и перенаправляет пользователя в форму входа, если они не прошли проверку подлинности (role = guest).

Когда пользователи отправляют свои учетные данные через форму входа в систему и проходят проверку подлинности, я хочу выполнить динамическое перенаправление в зависимости от того, как они достигли формы.

Динамическое перенаправление должно соответствовать следующим условиям:

  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 (потому что это бесполезно). Это означает, что пользователи, ищущие эту страницу, должны быть перенаправлены в другое место.

Но я также начал с предположения, что «редирект плох»:

  1. Если не достигнуто непосредственно, не должно быть никаких следов www.site.com/login в истории браузера.
    Это потому, что кнопка «Назад» браузера может испортить все, что сказано в пункте 2 (конфликт). Пример:

    • Я захожу на страницу site.com/user/post/2016?tag=foo, но я не вошел в систему или сеанс истек
    • Затем меня перенаправляют на www.site.com/login, где я заполняю форму аутентификации и отправляю ее
    • После аутентификации меня снова перенаправляют на 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 (если не через историю). (И это причина, почему я пытался работать с плагином вперед)

Решение, которое я нашел для достижения этой цели, заключается в использовании плагина перенаправления в дополнение к процессу переадресации «сделай сам», который работает с Routemach MVC.

Я начал писать код, следуя инструкции этого самсонасика: 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
->...

Все, что находится внутри гостевого модуля, должно быть доступным для общественности (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;
}

[...]

}

путь: Гость / src / Гость / Контроллер / 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
}

[...]
}

Я буду обновлять этот пост, если я найду некоторые другие проблемы, но пока он работает как шарм.

П.С .: Надеюсь, мои английские результаты читабельны. 🙂

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]