dongzaheng4449 2014-05-29 10:22
浏览 43
已采纳

如何使用FOSRestBundle和FOSOauthServerBundle保护REST API中的用户资源?

I'm developing a RESTful web service in Symfony2 with FOSRest and FOSOauthServer bundles (... and many others). My problem is that with an access token of other user, the api gives response instead of a 403 status code. For example:

I have two users stored on database

userA with tokenA userB with tokenB

Example Request http://example.com/api/v1/userA/products?access_token=tokenB

Current Response

{
   products: {
    0: { ... } 
    1: { ... }
  }
}

But I'm requesting products of user A with an access token of user B. How could I check if access token provided is of the products' owner??

My security.yml file:

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: sha512

    role_hierarchy:
        MY_ROLE:
            # ...
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
        SONATA:
            - ROLE_SONATA_PAGE_ADMIN_PAGE_EDIT
    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email

    firewalls:            
        admin:
            pattern:            /admin(.*)
            context:            user
            form_login:
                provider:       fos_userbundle
                csrf_provider:  form.csrf_provider
                login_path:     /admin/login
                use_forward:    false
                check_path:     /admin/login_check
                failure_path:   null
            logout: 
                path:           /admin/logout
            anonymous:          true                

        # FOSOAuthBundle and FOSRestBundle    
        oauth_token:
            pattern:    ^/oauth/v2/token
            security:   false

#        oauth_authorize: commented because there are not oauth login form on this app
#            pattern:    ^/oauth/v2/auth
            # Add your favorite authentication process here

        api:
            pattern:    ^/api
            fos_oauth:  true
            stateless:  true
            anonymous:  false

        # This firewall is used to handle the public login area
        # This part is handled by the FOS User Bundle
        main:
            # ...

    access_control:
        # ...

        # API (FOSRestBundle and FOSOAuthBundle)
        - { path: ^/api, roles: [IS_AUTHENTICATED_FULLY] }

My routing.yml on ApiBundle

# API Endpoints
app_api_user_get_products:
    pattern: /{username}/products
    defaults: { _controller: ApiBundle:User:getProducts, _format: json }
    methods: GET

My UserController.php

<?php

namespace App\ApiBundle\Controller;

Use App\MainBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// ... more use statments

    class UserController extends ApiController {

    /**
     * List user's products.
     *
     * @ApiDoc(
     *  resource = true,
     *  description="This method must have the access_token parameter. The parameters limit and offset are optional.",
     *  filters={
     *      {"name"="access_token", "dataType"="string", "required"="true"},
     *      {"name"="offset", "dataType"="integer", "default"="0", "required"="false"},
     *      {"name"="limit", "dataType"="integer", "default"="250", "required"="false"}
     *  },
     * )
     *
     * @Annotations\QueryParam(name="offset", requirements="\d+", nullable=true, description="Offset from which to start listing products.")
     * @Annotations\QueryParam(name="limit", requirements="\d+", default="500", description="How many products to return.")
     *
     * @Annotations\View()
     *
     * @param User               $user      the request object
     * @param ParamFetcherInterface $paramFetcher param fetcher service
     *
     * @return array
     */
    public function getProductsAction(User $user, ParamFetcherInterface $paramFetcher, Request $request) { 


//        $offset = $paramFetcher->get('offset');
//        $offset = null == $offset ? 0 : $offset;
//        $limit = $paramFetcher->get('limit');

        try {
            // estructure and exclude fields strategy http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies
            $data = array('products' => array());
            foreach ($user->getCatalog() as $p) {
                if ($p->getAvailable() == true) {
                    $product = $p->getProduct();
                    $data['products'][] = array(
                        'id' => $product->getId(),
                        'reference' => $product->getReference(),
                        'brand' => $product->getBrand(),
                        'description' => $product->getDescription(),
                        // ...
                    );
                }
            }
        } catch (\Exception $e) {
            throw new HttpException(Codes::HTTP_INTERNAL_SERVER_ERROR, $e->getTraceAsString());
        }

        // New view
        $view = new View($data);
        $view->setFormat('json');

        return $this->handleView($view);
    }
}

Thank you very much for the help!

  • 写回答

2条回答 默认 最新

  • dongshan9619 2014-05-29 11:14
    关注

    I've found the solution. It's easy, just I've added the following code in my rest controller and the configuration parameters on app/config.yml

    UserController.php

    ...
    public function getProductsAction(User $user, ParamFetcherInterface $paramFetcher, Request $request) {
    
            // Check if the access_token belongs to the user making the request
            $requestingUser = $this->get('security.context')->getToken()->getUser();
            if (!$requestingUser || $requestingUser !== $user) {
                    throw new AccessDeniedHttpException();
            }
    ...
    

    ~/app/config.yml

    # FOSRestBundle
    fos_rest:
        routing_loader:
            default_format: json
        param_fetcher_listener: true
        view:
            view_response_listener: force
        access_denied_listener: # I've added this
            # all requests using the 'json' format will return a 403 on an access denied violation
            json: true
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度