更改请求,从会话中检索数据

时间:2017-02-22 12:46:14

标签: symfony symfony-http-foundation

情景:

  • 我没有AJAX。
  • 我的搜索表单采用GET方法且csrf_protection已停用,可过滤myEntityListAction中显示和分页的实体,可在uri /myapp/myentity/list
  • 处找到
  • 用户打开/myapp/myentity/list,提交过滤器表单并转到第2页。他现在在/myapp/myentity/list?entity_filter[search]=something&page=2
  • 用户打开另一个页面(让我们说一个显示的实体的详细信息),然后点击/myapp/myentity/list

我希望他看到页面/myapp/myentity//list?entity_filter[search]=something&page=2

我正在尝试让过滤器对用户的会话变得很粘,以便当用户重新打开/myapp/myentity/list而没有任何参数时,他会获得上次看到的结果,并使用相同的过滤器和页码。

我遵循这种方法,但我认为它被高度弃用,因为我正在修改$request对象和$_GET超全局(由于直接使用$ _GET的分页库),尽管它有效。< / p>

/**
 * @Route("/myapp/myentity/list",  name="entity_list")
 * @Method({"GET"})
 */
public function myEntityListAction(Request $request) {
    if (0===$request->query->count()) { //querystring is empty
        $prev_query=$request->getSession()->get('my_entity_list', null);
        if ($prev_query) { //is there something in session?
            $_GET=$prev_query;
            $original_request=$request;
            $request=$request->createFromGlobals();
            $request->setSession($original_request->getSession());
        }
    } else { //i have something in my querystring
        $request->getSession()->set('my_entity_list', $request->query->all()); //i store it in session
    }
    //...do the other stuff (form, filters, pagination, etc)
}

我认为我会采用另一种方法,将用户重定向到/myapp/myentity/list?entity_filter[search]=something&page=2(从会话中读取),这样我就不必修改$_GET$request。< / p>

问题在于:如何在不进行重定向的情况下安全地编辑$ request以注入或更改我需要的内容?我可以通过子请求安全地完成它吗?

2 个答案:

答案 0 :(得分:2)

重新解释设置

您无法安全地编辑请求。不应在控制器内修改请求,因为它是您将使用它的“最后位置”(即使您也可以在视图中使用它)。这不太安全。

重定向基于响应,而不是请求。

(额外奖励:让用户在会话中重置(或“清除”)此信息是件好事。我建议您为此创建一个按钮。)

让我们重新解释一下你已经很好的情景:

  • 步骤1:
    用户转到/myapp/myentity/list
    查询和会话都没有 列表显示应该
  • 第2步:
    用户通过单击Page 2来提交搜索表单 表单提交使用户转到
    /myapp/myentity/list?entity_filter[search]=something&page=2
    发出此请求后,控制器将会话中的查询字符串保存为“上次查看的查询字符串”,即您已使用的my_entity_list会话参数。
    使用过滤器显示列表
  • 第3步:
    用户通过单击徽标返回/myapp/myentity/list,例如
    查询中没有任何内容。但在会议中有一些东西。 用户被重定向到/myapp/myentity/list?{last_query_string}
    然后回到第2步
  • 第4步:
    用户点击“清除过滤器”按钮 AJAX或普通请求无关紧要:任何控制器都会从会话中取消my_entity_list 将用户重定向到/myapp/myentity/list 回到第1步。

现在,代码

您的代码也必须使用类似的内容重新组织:

/**
 * @Route("/myapp/myentity/list",  name="entity_list")
 * @Method({"GET"})
 */
public function myEntityListAction(Request $request) {

    // First, get query string
    $queryStringArguments = $request->query->all();

    if (0 === count($queryStringArguments)) {
        $lastQueryStringArguments = $request->getSession()->get('my_entity_list', null);

        if ($lastQueryStringArguments) {
            // Just replace the var, don't manipulate the request
            $queryStringArguments = $lastQueryStringArguments;
        }
    }

    // Whatever the var is retrieved from request or session,
    // this will always be saved in session.
    if (count($queryStringArguments)) {
        $request->getSession()->set('my_entity_list', $queryStringArguments); //i store it in session
    }

    //...do the other stuff (form, filters, pagination, etc)
}

最后,最佳实践

在您的情况下,您所做的事情绝对是不安全进行注射。

您应该验证查询字符串并检索仅需要的数据

可以使用FormType或简单的手动验证来完成此操作,您应该取消设置所有不受欢迎/未使用的查询字符串参数以避免可能的注入。

使用类似$allowedParams = ['page', 'search_query', 'filter_by_id'];之类的变量或类似的变量非常简单,可以帮助您重置此数组中的所有键(因此不会将它们添加到会话中或操作中)您的表单使用html / javascript注入)

答案 1 :(得分:1)

您可以使用Before filter。在监听器中,检查您的会话,提取已保存的路径(或过滤器),并使用类似

之类的内容重定向(如果需要)
$event->setController(function() use ($redirectUrl) {
    return new RedirectResponse($redirectUrl);
});

您也可以使用$event->getRequest()获取请求并根据需要进行更改。