Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using forward/dispatch results in different RouteMatch class object #27

Closed
weierophinney opened this issue Dec 31, 2019 · 2 comments
Closed
Labels
Question Further information is requested

Comments

@weierophinney
Copy link
Member

This issue has been moved from the zendframework repository as part of the bug migration program as outlined here - http://framework.zend.com/blog/2016-04-11-issue-closures.html


Original Issue: https://api.github.com/repos/zendframework/zendframework/issues/7389
User: @kuldeep-k
Created On: 2015-03-31T08:32:24Z
Updated At: 2015-11-06T21:05:11Z
Body
I am building a rest based auth forwarding. So I do code like below in listener class

public function __invoke(MvcEvent $event)
{
    print_r($event->getRouteMatch());
    $result = $this->adapter->authenticate();
    $routeMatch = $event->getRouteMatch();

    if (!$result->isValid()) {

        $response = $event->getResponse();

        $response->setStatusCode(401);

        /*$routeMatch = $event->getRouteMatch();
        $routeMatch->setParam('controller', 'Rest\Controller\Error');
        $routeMatch->setParam('action', 'auth');
        */

        $cpm = $this->getServiceLocator()->get('ControllerPluginManager');
        $fwd = $cpm->get('forward');
        return $fwd->dispatch('Rest\Controller\Error', array('action' => 'auth'));
    }
}

So first time request comes for controller Rest\Controller\Index action index (matched route "rest") but due to authentication failure forward happens to controller Rest\Controller\Error action auth (matched route "rest-error")

However what is printed is below

Zend\Mvc\Router\Http\RouteMatch Object
(
    [length:protected] => 5
    [params:protected] => Array
        (
            [controller] => Rest\Controller\Index
        )

    [matchedRouteName:protected] => rest
)
Zend\Mvc\Router\RouteMatch Object
(
    [params:protected] => Array
        (
            [action] => auth
        )

    [matchedRouteName:protected] => rest
)
Zend\Mvc\Router\RouteMatch Object
(
    [params:protected] => Array
        (
            [action] => auth
        )

    [matchedRouteName:protected] => rest
)

Which show that first request go to Zend\Mvc\Router\Http\RouteMatch while subsequent request goes to Zend\Mvc\Router\RouteMatch ( Due to not check of safe route request recursively goes end throw expected error "Circular forwarding detected")

Now from second request do not have controller information also, It matched to wrong matchedRouteName.

module.config.php have these routes

'routes' => array(
    'rest' => array(
        'type' => 'Zend\Mvc\Router\Http\Segment',
        'options' => array(
            'route'    => '/rest[/:id]',
            'constraints' => array(
                'id'     => '[0-9]+',
            ),
            'defaults' => array(
                'controller' => 'Rest\Controller\Index'
            ),
        ),
    ),
    'rest-error' => array(
        'type' => 'Zend\Mvc\Router\Http\Segment',
        'options' => array(
            'route'    => '/resterror',
            'constraints' => array(
                'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                'id'     => '[0-9]+',
            ),
            'defaults' => array(
                'controller' => 'Rest\Controller\Error',
                'action'     => 'auth',
            ),
        ),
    )
),

I tried on Zend Framework v2.3.4 & v2.2.4 .



Originally posted by @GeeH at zendframework/zend-mvc#174

@goharsahi
Copy link

goharsahi commented Aug 7, 2022

I'm experiencing somewhat similar issue. My Listener code is below

    public function userHasAuthentication(MvcEvent $e)
    {
        $routeMatch = $e->getApplication()
            ->getServiceManager()
            ->get("HttpRouter")
            ->match($e->getRequest());

        if ($routeMatch) {
            $controllerName = explode("\\", $routeMatch->getParam("controller"))[2];
            $actionName = $routeMatch->getParam("action");
            $actionName = str_replace("-", "", lcfirst(ucwords($actionName, "-")));
            $moduleName = explode("\\", $routeMatch->getParam("controller"))[0];
            if ($controllerName !== "UserController"
                && $actionName !== "login"
                && $actionName !== "logout"
            ) {
                $result = $this->getLoginService()
                    ->filterAccess($moduleName, $controllerName, $actionName, $taskName = "*");

                if ($result == LoginService::AUTH_REQUIRED) {
                    $routeMatch->setParam("controller", UserController::class);
                    $routeMatch->setParam("action", "login");
                }

                if ($result == LoginService::ACCESS_DENIED) {
                    $routeMatch->setParam("controller", UserController::class);
                    $routeMatch->setParam("action", "unauthorized");
                    $e->getResponse()
                        ->setStatusCode(401);
                }
            }
        }
    }
//Router code

'home' => [
    'type' => Literal::class,
    'options' => [
        'route' => '/',
        'defaults' => [
            'controller' => Controller\IndexController::class,
            'action' => 'index',
        ],
    ],
],
'dashboard' => [
    'type' => Literal::class,
    'options' => [
        'route' => '/dashboard',
        'defaults' => [
            'controller' => Controller\IndexController::class,
            'action' => 'dashboard',
        ],
    ],
],       

Module::ROUTE_NAME_MODULE => [ // user
    "type" => Segment::class,
    "options" => [
        "route" => Module::ROUTE_PREFIX,
        "defaults" => [
            "controller" => UserController::class,
            "action" => "index",
        ],
    ],
    "may_terminate" => true,
    "child_routes" => [
        Module::ROUTE_NAME_ACTIONS => [ //actions ===> results in user/actions
            "type" => Segment::class,
            "options" => [
                "route" => "/:action[/:id]",
                "constraints" => [
                    "action" => "[a-zA-Z][a-zA-Z0-9_-]*",
                    "id" => "[0-9]+",
                ],
            ],
        ],
    ],
], 

All works as per the code except below.

[matchedRouteName:protected] => dashboard

This is always dashboard, due to which instead of routing to unauthorized action of Controller\UserController::class it was routes to dashboard action of Controller\IndexController::class.

If I use the below code

$routeMatch->setMatchedRouteName(
                        "user/actions"
                    );

It keeps suffixing it to original matchedRouteName i.e. dashboard which sometimes becomes something like

[matchedRouteName:protected] => user/actions/user/actions/user/actions/user/actions/dashboard

P.S. I don't want to use onDispatch as I want this listener to execute before dispatching the route.

Thanks.

@froschdesign froschdesign added the Question Further information is requested label Aug 8, 2022
@froschdesign
Copy link
Member

@goharsahi
Please use the forum for support questions.
Thanks in advance! 👍🏻

@froschdesign froschdesign closed this as not planned Won't fix, can't repro, duplicate, stale Aug 8, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants