我正在使用FOSRest和FOSOauthServer捆绑包(......和许多其他捆绑包)在Symfony2中开发RESTful Web服务。我的问题是,使用其他用户的访问令牌,api给出响应而不是403状态代码。例如:
我有两个用户存储在数据库
上userA with tokenA userB with tokenB
示例请求 http://example.com/api/v1/userA/products?access_token=tokenB
当前回应
{
products: {
0: { ... }
1: { ... }
}
}
但我要求用户A的产品使用用户B的访问令牌。我如何检查提供的访问令牌是否属于产品所有者?
我的security.yml文件:
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] }
我在ApiBundle上的routing.yml
# API Endpoints
app_api_user_get_products:
pattern: /{username}/products
defaults: { _controller: ApiBundle:User:getProducts, _format: json }
methods: GET
我的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);
}
}
非常感谢您的帮助!
答案 0 :(得分:1)
我找到了解决方案。这很容易,只是我在我的rest控制器中添加了以下代码,并在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();
}
...
〜/应用程序/ 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 :(得分:0)
您还可以使用Symfony&gt; = 2.4中的@Security注释使其更简单。在你的情况下,它看起来像
/**
* @Security("user.getId() == userWithProducts.getId()")
*/
和动作标题:
...
public function getProductsAction(User $userWithProducts, ParamFetcherInterface $paramFetcher, Request $request) {
...