2014-02-19 1 views
7

Slim으로 REST API를 작성하고 있습니다.Slim PHP : 미들웨어로 유효한 경로 만 잡으십시오.

<?php 
class SecurityMiddleware extends \Slim\Middleware 
{ 
    protected $resource; 
    public function __construct($resource) 
    { 
     $this->resource = $resource; 
    } 
    public function call() 
    { 
     //get a reference to application 
     $app = $this->app; 
     //skip routes that are exceptionally allowed without an access token: 
     $publicRoutes = ["/","/login","/about"]; 
     if (in_array($app->request()->getPathInfo(),publicRoutes)){ 
      $this->next->call(); //let go 
     } else { 
      //Validate: 
      if ($this->resource->isValid()){ 
       $this->next->call(); //validation passed, let go 
      } else { 
       $app->response->setStatus('403'); //validation failed 
       $app->response->body(json_encode(array("Error"=>"Access token problem"))); 
       return; 
      } 
     } 
    } 
} 

이 작동하지만, 바람직하지 않은 부작용이 기존 경로와 비 사이에 구별을하지 않습니다 미들웨어 : 나는 인증 된 사용자 만이 그들을 액세스 할 수 있도록 자원을 보호하기 위해 작은 미들웨어를 작성했습니다 기존 경로. 예를 들어, 사용자가 존재하지 않는 /dfghdfgh과 같은 경로를 요청하려고 시도하면 404라는 HTTP 상태 코드를받는 대신 액세스 토큰이 없다는 403이라는 메시지가 표시됩니다. 미들웨어 클래스에 대해 다음과 유사한 구현을 추가하고자합니다.

if ($app->hasRoute($app->request->getPathInfo()){ 
    $this->next->call(); //let go so user gets 404 from the app. 
} 

어떻게 구현할 수 있습니까?

답변

2

당신이 요구하는 것은 아니지만, 일부 경로에서 인증을 확인해야 할 때 personnaly입니다.

설정 :

$config = array(
    ..., 

    'user.secured.urls' => array(
     array('path' => '/user'), 
     array('path' => '/user/'), 
     array('path' => '/user/.+'), 
     array('path' => '/api/user/.+') 
    ), 
    ... 

); 

미들웨어 :

/** 
* Uses 'slim.before.router' to check for authentication when visitor attempts 
* to access a secured URI. 
*/ 
public function call() 
{ 
    $app = $this->app; 
    $req = $app->request(); 
    $auth = $this->auth; 
    $config = $this->config; 

    $checkAuth = function() use ($app, $auth, $req, $config) { 

     // User restriction 
     $userSecuredUrls = isset($config['user.secured.urls']) ? $config['user.secured.urls'] : array(); 
     foreach ($userSecuredUrls as $url) { 
      $urlPattern = '@^' . $url['path'] . '[email protected]'; 
      if (preg_match($urlPattern, $req->getPathInfo()) === 1 && $auth->hasIdentity() === false) { 

      $errorData = array('status' => 401,'error' => 'Permission Denied'); 
      $app->render('error.php', $errorData, 401); 
      $app->stop();     
     } 
    } 

    }; 

    $app->hook('slim.before.router', $checkAuth); 

    $this->next->call(); 
} 

하지만 거의 모든 노선 아마 최고의 솔루션을위한 인증을하지 필요합니다.

좋은 예 : http://www.slideshare.net/jeremykendall/keeping-it-small-slim-php

+0

감사합니다. 따라서 기본적으로 반대 방향을 취하고 있습니다. 공개적으로 사용 가능한 경로를 버리는 대신 인증이 필요한 경로를 잡는 것입니다. 필자의 경우 거의 모든 리소스가 인증을 필요로하므로이 접근 방식이 내 유스 케이스에 맞지 않는다고 생각합니다. – user1555863

5

난 당신이 MamaWalter이 제안, 뭘 하려는지 할 수있는 hook을 사용하지만 이전 후크보다는 slim.before.dispatch를 사용하고 싶습니다. 사용자가 방문하려는 경로가 존재하지 않으면 후크가 호출되지 않고 404이 던져 질 것입니다.

나는 내 자신의 것으로 정확히 이것을하고있다 Authorization Middleware. 매력처럼 작동합니다.

+0

+1 정말 좋은데, 분명히 사용할 것입니다. – MamaWalter

+0

나는 방금 내가 쓴 튜토리얼을 썼다는 것을 깨달았고 나의 예는 당신의 작업에 기반하고있다. 좋은 일, 정말 도움이된다 ... 미안하지만 나는 언급해야한다. – MamaWalter

+0

정말 멋지다! 나는 그것이 친숙한 것으로 생각했다. 비슷하게 생각하는 것은 위대한 마음의 사건 일 뿐이라고 생각했습니다 .- 권장 된 훅을 변경하기 위해 메소드의 docblock을 업데이트해야하는 것처럼 보입니다. –

2

어쩌면 내 구현은 당신을 위해 작동합니다 : 대답에 대한

<?php 

class CustomAuth extends \Slim\Middleware { 

    public function hasRoute() { 
     $dispatched = false; 

     // copied from Slim::call():1312 
     $matchedRoutes = $this->app->router->getMatchedRoutes($this->app->request->getMethod(), $this->app->request->getResourceUri()); 
     foreach ($matchedRoutes as $route) { 
      try { 
       $this->app->applyHook('slim.before.dispatch'); 
       $dispatched = $route->dispatch(); 
       $this->app->applyHook('slim.after.dispatch'); 
       if ($dispatched) { 
        break; 
       } 
      } catch (\Slim\Exception\Pass $e) { 
       continue; 
      } 
     } 

     return $dispatched; 
    } 

    public function call() { 

     if ($this->hasRoute()) { 
      if ($authorized) { 
       $this->next->call(); 
      } 
      else { 
       $this->permissionDenied(); 
      } 
     } 
     else { 
      $this->next->call(); 
     } 
    } 
} 
관련 문제