使用Event組件如何設置先後過濾器

可能咱們在某些時候須要在某一個動做先後執行一些邏輯一個;咱們能夠經過事件機制來完成php

##一個Token驗證的例子數據庫

假如你開發了一個API;有的資源能對外開放;有的須要驗證才能訪問資源;這就須要咱們對請求來判斷是否訪問了須要的資源;以及他們所攜帶的token是否正確app

####使用kernel.controller事件來前置過濾器this

定義一些對外的token參數;注意這些也能夠在數據庫中配置加密

# app/config/config.yml
parameters:
    tokens:
        client1: pass1
        client2: pass2

定義一個接口;以便區分哪些控制器須要驗證spa

namespace AppBundle\Controller;

interface TokenAuthenticatedController
{
    // ...
}

定義控制器;實現了上述的接口的控制器就須要驗證才能訪問code

namespace AppBundle\Controller;

use AppBundle\Controller\TokenAuthenticatedController;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class FooController extends Controller implements TokenAuthenticatedController
{
    // An action that needs authentication
    public function barAction()
    {
        // ...
    }
}

####建立一個事件監聽者orm

// src/AppBundle/EventListener/TokenListener.php
namespace AppBundle\EventListener;

use AppBundle\Controller\TokenAuthenticatedController;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

class TokenListener
{
    private $tokens;

    public function __construct($tokens)
    {
        $this->tokens = $tokens;#構造注入
    }

    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();

        /*
         * $controller passed can be either a class or a Closure.
         * This is not usual in Symfony but it may happen.
         * If it is a class, it comes in array format
         */
        if (!is_array($controller)) {
            return;
        }

        //驗證傳入的token是否正確
        if ($controller[0] instanceof TokenAuthenticatedController) {
            $token = $event->getRequest()->query->get('token');
            if (!in_array($token, $this->tokens)) {
                throw new AccessDeniedHttpException('This action needs a valid token!');
            }
        }
    }
}

####註冊監聽者token

# app/config/services.yml
services:
    app.tokens.action_listener:
        class: AppBundle\EventListener\TokenListener
        arguments: ['%tokens%']#把上面配置的tokens參數注入給監聽者類
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

###使用kernel.response事件構造後置過濾器接口

假如咱們上面的例子;客戶token正確;訪問資源完畢;咱們須要回調給客戶數據;客戶那邊也須要驗證; 這時候咱們就可使用 該事件了;

//這是kernel.controller事件調用
public function onKernelController(FilterControllerEvent $event)
{
    // ...

    if ($controller[0] instanceof TokenAuthenticatedController) {
        $token = $event->getRequest()->query->get('token');
        if (!in_array($token, $this->tokens)) {
            throw new AccessDeniedHttpException('This action needs a valid token!');
        }

        //驗證經過;標記一下回調的auth_token
        $event->getRequest()->attributes->set('auth_token', $token);
    }
}


//這個是 kernel.response事件分發時候調用的
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;

public function onKernelResponse(FilterResponseEvent $event)
{
    //檢查是否設置了auth_token
    if (!$token = $event->getRequest()->attributes->get('auth_token')) {
        return;
    }

    $response = $event->getResponse();

    // 建立一個response header放入加密信息;
    $hash = sha1($response->getContent().$token);
    $response->headers->set('X-CONTENT-HASH', $hash);
}

####註冊監聽者

# app/config/services.yml
services:
    app.tokens.action_listener:
        class: AppBundle\EventListener\TokenListener
        arguments: ['%tokens%']
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
            - { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }
相關文章
相關標籤/搜索