5

我有一个使用 FOSOAuthServerBundle 对用户进行身份验证的基本 api。用户可以具有 ROLE_USER 和 ROLE_ADMIN 角色。基于 FOSOAuthServerBundle 文档,默认行为是使用作用域作为角色,所以我认为当我有一个普通用户时,包会scope: user在响应中返回,而当它是管理员用户时,会返回scope: admin. 但它不是这样工作的。supported_scopes捆绑包返回条目中配置的任何内容。下面是我的config.yml

fos_oauth_server:
    service:
        options:
            supported_scopes: user admin

我的access_control部分security.yml是空的,我的firewalls部分如下:

firewalls:
        users_create:
            pattern: ^/v1/users
            methods: [POST]
            security: false

        api:
            pattern:    ^/
            security: true
            fos_oauth:  true
            stateless:  true

access_control:
        # You can omit this if /api can be accessed both authenticated and anonymously

这样user admin,即使用户没有 ROLE_ADMIN 角色,捆绑包总是作为范围返回。

{
"access_token": "ZGQ2ODE5ZjAzNTZkOWY0OWMyNmZmODE4MjcwZTJmYjExNzY0NzQxOTRmMzk4NzA2Mjc2NjIyZmY1ZDgwMzk4NA"
"expires_in": 3600
"token_type": "bearer"
"scope": "user admin"
"refresh_token": "NmM5ZGFmNzBiNTNjYmQzMTQ1MTk0ODJjOTAxMWU0YWIwMzM1MzgyODg4ZTAzNTI5ZTk2MDc3OGU2MTg0MWZiMA"
}

我错过了什么?用户角色不是附加到令牌范围吗?有没有更好的方法来知道我的用户是否是管理员?

4

4 回答 4

2

doc中,默认行为是将范围与角色进行映射。在您的情况下,角色将是 ROLE_USER 和 ROLE_ADMIN。

现在为了限制使用,您可以像这样编辑您的 security.yml 文件:

# app/config/security.yml
security:
    access_control:
        - { path: ^/api/super/secured, role: ROLE_ADMIN }
        - { path: ^/api/general, role: ROLE_USER }

要限制控制器内部的访问,您可以使用以下命令:

if ($this->get('security.context')->isGranted('ROLE_ADMIN')) {
    // the user has the ROLE_ADMIN role, so act accordingly
}

再次来自文档

现在,客户端在请求访问令牌时将能够传递范围参数。

希望这可以帮助。

更新:

在此处查看类似问题的答案以及有关设置 FOSOAuthServerBundle 的文章。密切关注配置部分。

于 2016-02-02T16:46:20.830 回答
1

github 上有一个问题可以追溯到 2013 年。如果您阅读了该问题并点击链接,您最终会发现用户 Spomky 创建了他自己的库和 Symfony 包,并被建议作为FOSAuthServerBundle 的维护者。看起来 FOS 组织将在 Spomky 的工作稳定后将其合并到 FOSOAuthServerBundle 的下一个主要版本中。

于 2016-03-17T10:20:25.070 回答
1

FOSOAuthServerBundle根据令牌对用户进行身份验证,因此您不必担心范围,这与角色不同。在您的控制器内部,您$this->getUser()可以获得当前经过身份验证的用户。如果这有效,那么检查是否isGranted也有效。

http://symfony.com/doc/current/book/security.html

public function helloAction($name)
{
    // The second parameter is used to specify on what object the role is tested.
    $this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');

    // Old way :
    // if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
    //     throw $this->createAccessDeniedException('Unable to access this page!');
    // }

    // ...
}

如果 $this->getUser()不起作用,您将不得不fetchEAGER实体上AccessToken设置。

class AccessToken extends BaseAccessToken
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Client")
     * @ORM\JoinColumn(nullable=false)
     */
    protected $client;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", fetch="EAGER")
     */
    protected $user;
}
于 2016-02-03T10:21:24.827 回答
0

您可以将用户帐户信息与令牌一起返回。

这是我处理类似情况的方法,我创建了一个代理路由,将用户名和密码作为请求参数,将 oauth 客户端信息添加到请求中,并将请求转发到 Oauth 令牌操作。然后我获取该信息并将用户信息与令牌一起返回。

/**
 * @REST\Post("/authorize")
 */
public function loginAction(Request $request){
    $request->request->add( array(
        'grant_type' => 'password',
        'client_id' => $this->container->getParameter('oauth_client_id') . "_" . $this->container->getParameter('oauth_client_random_id'),
        'client_secret' => $this->container->getParameter('oauth_client_secret')
    ));
    $tokenAction = $this->get('fos_oauth_server.controller.token')->tokenAction($request);
    $tokenObject = json_decode( $tokenAction->getContent() );

    if(key_exists('error_description', $tokenObject)){
        return $this->view(["error" => $tokenObject->error_description], 401);
    };


    $user = $this->getDoctrine()->getRepository('\App\Entity\Oauth\AccessToken')->findOneBy( array('token' => $tokenObject->access_token ) )->getUser();
    $return = array(
        "roles" => $user->getUser()->getRoles(),
        "access_token" => $tokenObject->access_token,
        "expires_in" => $tokenObject->expires_in,
        "token_type" => $tokenObject->token_type,
        "scope" =>$tokenObject->scope,
        "refresh_token" => $tokenObject->refresh_token
    );
    return $this->view($return);
}

我使用此路由进行身份验证/令牌生成,而不是使用 OAuthBundle 附带的路由

于 2018-05-14T18:25:30.980 回答