2017-02-22 28 views
0

目標是將用戶重定向到中間件的登錄頁面。 中間件從超薄路線組此行稱爲:正確的方式從薄中間件重定向

$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; 
    } 

} 

我的目標是當中間件檢測到用戶當前沒有登錄,則將用戶重定向到登錄頁面。 你可以看到我目前的方式很糟糕:我使用了一個重定向,然後是一個退出。

我怎樣才能用適當的「苗條」方式取代這兩條線?

回答

2

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'); 

現在,您可以通過名稱指的路線,而非網址本身的中間件。對於那些你需要注入修身路由器對象:

<?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->pathFor()訪問方法。

我會說這是非常苗條,不錯的方式。 )

+0

非常好!我其實從來沒有真正查看過路徑上的setName方法。不是中間件或類中硬編碼路由的粉絲。 – Rob