【问题标题】:Proper way to redirect from slim middleware从超薄中间件重定向的正确方法
【发布时间】:2017-02-22 21:03:52
【问题描述】:

目标是将用户从中间件重定向到登录页面。 中间件是从一个纤细的路由组中调用的:

$this->get( '/profile', ProfileController::class . ':index' )->add( new RequireLogin() );

这是中间件

<?php

namespace Rib\Src\MiddleWares;


use Rib\Src\Services\FlashMessages;
use Slim\Http\Request;
use Slim\Http\Response;

class RequireLogin
{


    /**
     * Example middleware invokable class
     *
     * @param  \Psr\Http\Message\ServerRequestInterface $request PSR7 request
     * @param  \Psr\Http\Message\ResponseInterface $response PSR7 response
     * @param  callable $next Next middleware
     *
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function __invoke( $request, $response, $next )
    {

        if ( ! isset( $_SESSION[ 'id' ] ) ) {
            FlashMessages::flashIt( 'message', "The page you tried to access requires an active session. Please log back in." );
            header( 'Location: /user/login' ); # THIS LINE
            exit; # AND THIS ONE
        }



        $response = $next( $request, $response );

        return $response;
    }

}

我的目标是当中间件检测到用户当前未登录时,将用户重定向到登录页面。 你可以看到我目前的方式很糟糕:我使用重定向然后退出。

如何用正确的“苗条”方式替换这两行?

【问题讨论】:

    标签: php slim


    【解决方案1】:

    Response有一个方便的方法withRedirect(),可以这样使用:

    <?php
    
    if (!isset($_SESSION[ 'id' ])) {
        FlashMessages::flashIt( 'message', "The page you tried to access requires an active session. Please log back in." );
        $url = '/user/login';
        return $response->withRedirect($url);
    } else {
        return $next($request, $response);
    }
    

    但是仍然存在一个问题:您正在硬编码您希望将未经身份验证的用户重定向到的 URL。考虑通过其名称获取该 URL(您可以在声明路由时给出):

    <?php
    
    // Add unique name to the route so you can 
    // refer to it later in the code (this is what we're going to do now)
    $app->get('/user/login', YourController::class)->setName('userLoginPage');
    

    现在您可以通过名称引用该路由,而不是中间件中的 URL 本身。为此,您需要注入 Slim Router 对象:

    <?php
    
    namespace Rib\Src\MiddleWares;
    
    
    use Rib\Src\Services\FlashMessages;
    use Slim\Http\Request;
    use Slim\Http\Response;
    use Slim\Router;
    
    class RequireLogin
    {
        /**
         * Object constructor
         * 
         * Inject Slim Router here, so you can access route names.
         * 
         * @param Router $router 
         */
        public function __construct(Router $router)
        {
            $this->router = $router;
        }
    
        /**
         * Example middleware invokable class
         *
         * @param  \Psr\Http\Message\ServerRequestInterface $request PSR7 request
         * @param  \Psr\Http\Message\ResponseInterface $response PSR7 response
         * @param  callable $next Next middleware
         *
         * @return \Psr\Http\Message\ResponseInterface
         */
        public function __invoke( $request, $response, $next )
        {
    
            if ( ! isset( $_SESSION[ 'id' ] ) ) {
                FlashMessages::flashIt( 'message', "The page you tried to access requires an active session. Please log back in." );
                // Get url by name: this is more flexible than hardcoding URL
                $url = $this->router->pathFor('userLoginPage') . ' #forbidden';
                return $response->withRedirect($url);
            } else {
                return $next( $request, $response );
            }
        }
    
    }
    

    这里的好处是,当您更改用户登录页面的实际 URL 时,您不必在中间件中更改它,因为它是通过 $router-&gt;pathFor() 方法访问的。

    我会说这是非常苗条的好方法。 )

    【讨论】:

    • 非常好!实际上,我从未真正研究过路线上的 setName 方法。不喜欢中间件或类中的硬编码路由。
    猜你喜欢
    • 2017-03-04
    • 1970-01-01
    • 2015-10-12
    • 2017-04-02
    • 1970-01-01
    • 2010-10-23
    • 1970-01-01
    • 2021-11-01
    • 2021-01-03
    相关资源
    最近更新 更多