将oAuth从控制器迁移到中间件

时间:2018-03-01 16:44:12

标签: php slim middleware slim-3

我正在使用This库来实现与Oauth的API,我想要对某些路由进行中间件,但我希望在其他中间件之前运行ouath,所以如果我错了,请纠正我这样做的方法是使oAuth成为中间件而不是控制器的一部分。

实际设置是这样的。

依赖项文件就像这样

$container['oAuth'] = function ($c) {

    $storage = new App\DataAccess\_oAuth2_CustomStorage($c->get('pdo'));

    // Pass a storage object or array of storage objects to the OAuth2 server class
    $server = new OAuth2\Server($storage);

    // add grant types
    $server->addGrantType(new OAuth2\GrantType\UserCredentials($storage));
    $server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage));
    $server->addGrantType(new OAuth2\GrantType\RefreshToken($storage));

    return $server;
};
$container['App\Controllers\_Controller_oAuth2'] = function ($c) {
    return new _Controller_oAuth2($c->get('logger'), $c->get('App\DataAccess\_DataAccess'), $c->get('oAuth'));
};

实际控制器是这样的:

public function __construct(LoggerInterface $logger, _DataAccess $dataaccess, $server)
    {
        parent::__construct($logger,$dataaccess);
        $this->oAuth2server = $server;
    }

     /**
     * @param \Psr\Http\Message\ServerRequestInterface $request
     * @param \Psr\Http\Message\ResponseInterface      $response
     * @param array                                    $next
     *
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function validateToken($request)
    {
        $this->logger->info(substr(strrchr(rtrim(__CLASS__, '\\'), '\\'), 1).': '.__FUNCTION__);

        // convert a request from PSR7 to hhtpFoundation
        $httpFoundationFactory = new HttpFoundationFactory();
        $symfonyRequest = $httpFoundationFactory->createRequest($request);
        $bridgeRequest = BridgeRequest::createFromRequest($symfonyRequest);
        $token = $this->oAuth2server->getAccessTokenData($bridgeRequest);

        if (!$this->oAuth2server->verifyResourceRequest($bridgeRequest)) {
            $this->oAuth2server->getResponse()->send();
            die;
         }

        // store the user_id
        $token = $this->oAuth2server->getAccessTokenData($bridgeRequest);
        $this->user = $token['user_id'];

        return TRUE;
    }

    // needs an oAuth2 Client credentials grant
    // with Resource owner credentials grant alseo works
    public function getAll(Request $request, Response $response, $args) {
        if ($this->validateToken($request)) {
            parent::getAll($request, $response, $args);

        }           
    }

现在,我尝试的是在我的中间件文件上创建我的函数,将其添加到所需的路由中,它看起来像这样:

$oathMiddleWare = function ($request,$response,$next){

    $container = $this->$app->getContainer();
    $responsen = $response->withHeader('Content-Type', 'application/json');

    $this->oAuth2server = $container->get('oAuth');

    $httpFoundationFactory = new HttpFoundationFactory();
        $symfonyRequest = $httpFoundationFactory->createRequest($request);
        $bridgeRequest = BridgeRequest::createFromRequest($symfonyRequest);
        $token = $this->oAuth2server->getAccessTokenData($bridgeRequest);

        if (!$this->oAuth2server->verifyResourceRequest($bridgeRequest)) {
            $this->oAuth2server->getResponse()->send();
            $responsen = $responsen ->withStatus(400);
            return $responsen;
         }

        // store the user_id
        $token = $this->oAuth2server->getAccessTokenData($bridgeRequest);
        $this->user = $token['user_id'];
        $next($request,$responsen);
        return $responsen;

};

我首先尝试$container = $app->getContainer();,但它给了我一个错误Call to a member function getContainer() on null

现在使用我刚刚分享的代码我收到错误Type: Slim\Exception\ContainerValueNotFoundException Message: Identifier “” is not defined.

有任何建议使这项工作?

1 个答案:

答案 0 :(得分:0)

要访问中间件中的容器,您可以执行以下操作:

1 /在特定文件和类中创建中间件

<?php
namespace api\middlewares;

class SecurityMiddleware
{
    public function __invoke($request, $response, $next)
    {
        // do your thing
        $response = $next($request, $response);

        return $response;
    }
}

2 /使用此类的构造函数来设置容器并在中间件

中访问它
private $container;

public function __construct($container)
{
    $this->container = $container;
}

3 /添加像这样的中间件

// security check
$app->add(new \api\middlewares\SecurityMiddleware($app->getContainer()));

我基于另一个api骨架制作了一个Slim 3 API骨架,我使用这种技术&amp; amp; oAuth2身份验证以及我在每个控制器中定义路由安全性的位置。您可以查看它是否对您有所帮助:https://github.com/mickaeleuranie/slim-api(当我有时间的时候,我会添加JWT和通话比率)

我所做的是通过定义一个受Yii框架启发的数组来定义每个控制器内部的访问权限:

public function accessRules()
{
    return [
        [
            'allow' => true,
            'actions' => [
                'edit',
            ],
            'roles' => ['@'],
        ],
        [
            'allow' => true,
            'actions' => [
                'get',
            ],
            'roles' => ['@'],
            'scopes' => 'admin',
        ],
        [
            'allow' => true,
            'actions' => [
                'login',
                'sociallogin',
                'signup',
                'contact',
            ],
            'roles' => ['?'],
        ],
    ];
}

通过这种方式,我可以从我的中间件访问控制器的规则,并检查用户是否可以访问此路由,具体取决于是否已记录,以及是否拥有其中一个授权角色。 / p>