7

注意:问题在本文的末尾,但我将详细解释所有上下文以便更好地理解。

我正在开发一个由 3 个模块组成的 Symfony2 应用程序:

  1. 学生模块-> 需要角色ROLE_STUDENT
  2. 教师模块-> 需要角色ROLE_TEACHER
  3. 管理员模块-> 需要角色ROLE_ADMIN

角色层次结构如下:

  • ROLE_TEACHER:[ROLE_STUDENT]
  • ROLE_ADMIN:[ROLE_TEACHER]

所以:

学生(具有 ROLE_STUDENT 角色)只能访问其模块的所有页面,例如:

教师(具有 ROLE_TEACHER 角色)可以访问学生模块的所有页面和教师模块的所有页面,例如:

管理员(具有 ROLE_ADMIN 角色)可以访问学生模块的所有页面、教师模块的所有页面和后台管理。

系统使用 OAuth 通过 Twitter 对学生和教师进行身份验证,使用捆绑包HWIOAuthBundle(使用提供捆绑包的 OAuthUserProvider用户提供程序)。

我已经成功地对用户进行身份验证,但默认情况下,所有用户都会自动使用以下角色进行身份验证: [ROLE_USER, ROLE_OAUTH_USER]


所以这就是我所做的。下面,我将解释我想要我的应用程序做什么,但我不知道怎么做:

使用 OAuth 登录的步骤:

用户登录系统并自动:

  • 如果数据库中不存在用户:
    - 将昵称保存在数据库的用户表中。
    - 在数据库的用户表中保存角色 ROLE_STUDENT(这是我默认的角色)。
    -使用 OAuth 但使用 ROLE_STUDENT 角色在系统中进行身份验证。

  • 如果用户存在于数据库中:
    - 检查数据库中与用户相关联的角色。
    -使用 OAuth 验证系统中的用户,但使用数据库中关联的角色(即:ROLE_STUDENT 或 ROLE_TEACHER)。

管理员(来自管理后端)可以查看昵称列表(由 Twitter 使用但保存在数据库中)以及为每个昵称分配的角色。管理员应该能够在 ROLE_STUDENT 和 ROLE_TEACHER 之间更改用户的角色。


问题:

  1. 我如何通过 OAuth (HWIOAuthBundle) 使用我想要的默认角色(如上所述的 ROLE_STUDENT)对用户进行身份验证?

  2. 如果数据库中存在具有关联角色(ROLE_STUDENT 或 ROLE_TEACHER)的昵称,我如何通过 OAuth(HWIOAuthBundle)验证用户但使用从数据库加载的角色?

我已经阅读了很多关于这个主题的内容,但我是 Symfony2 的新手,我不知道解决它的最好和最简单的方法是什么。

先感谢您!

PS:如果您对任何事情有任何疑问或疑问,我很乐意尽可能地解释。

4

1 回答 1

11

更新:

我尝试在我最近的一个项目中使用此代码,但它不再起作用了。原因是 HWIOAuthBundle 更新了几次,配置文件不一样。我将代码放在上面,并在 github 中登录了其他一些社交网络,您可以在HWIOAuthBundleByExample中找到。


我有一周的 symfony2 经验,在过去的几天里,这就是我自己的工作。今天找到了你的问题(当我还在研究的时候)。

我将根据哪些数据以及我是如何做到的,向您展示我必须做的事情。之后,我将尝试为您提供一些关键链接,希望您能够根据自己的需要进行建模。

我的应用需要 Facebook 登录和管理员角色。因为只会是几个管理员,所以我在认证的时候只需要几个Facebook ID,所以我将它们存储在一个yaml数组中。(见最后如何从数据库中加载它们)。

这是我所做的:

#/app/config.yml #the setup looks different (I need the picture and email credentials)
hwi_oauth:
  # name of the firewall in which this bundle is active, this setting MUST be set
  firewall_name: secured_area
  resource_owners:
    facebook:
      type:        facebook
      client_id:       %facebook_client_id%
      client_secret:     %facebook_client_secret%
      scope:         "email"
      infos_url:     "https://graph.facebook.com/me?fields=username,name,email,picture.type(square)"
      paths:
        email:          email
        profilepicture: picture.data.url
services: #here's where the magic happens
  hwi_oauth.user.provider.entity:
    class: HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUserProvider
  ib_user.oauth_user_provider:
    class: Acme\DemoBundle\Provider\Provider
    arguments: [@session, @doctrine, %admins%]

#app/security.yml
security:
  providers:
    my_custom_hwi_provider:
      id: ib_user.oauth_user_provider

  access_control:
        - { path: ^/admin, roles: ROLE_SUPER_ADMIN }



#app/parameters.yml
parameters:
  #...
  facebook_client_id:     ###
  facebook_client_secret: ###
  admins:
    - "my.facebook.id"

#Acme\DemoBundle\Provider\Provider
<?php

namespace Acme\DemoBundle\Provider;

use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUserProvider;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use Acme\DemoBundle\Entity\User;
use Acme\DemoBundle\Provider\OAuthUser;

class Provider extends OAuthUserProvider
{
    protected $session, $doctrine, $admins;
    public function __construct($session, $doctrine, $admins) {
        $this->session = $session;
        $this->doctrine = $doctrine;
        $this->admins = $admins;
    }

    public function loadUserByUsername($username)
    {
        return new OAuthUser($username, $this->isUserAdmin($username)); //look at the class below
    }

    private function isUserAdmin($nickname)
    {
        return in_array($nickname, $this->admins);
    }

    public function loadUserByOAuthUserResponse(UserResponseInterface $response)
    {
        //data from facebook response
        $facebook_id = $response->getUsername();
        $nickname = $response->getNickname();
        $realname = $response->getRealName();
        $email    = $response->getEmail();
        $avatar   = $response->getProfilePicture();

        //set data in session
        $this->session->set('nickname', $nickname);
        $this->session->set('realname', $realname);
        $this->session->set('email', $email);
        $this->session->set('avatar', $avatar);

        //get user by fid
        $qb = $this->doctrine->getManager()->createQueryBuilder();
        $qb ->select('u.id')
            ->from('AcmeDemoBundle:User', 'u')
            ->where('u.fid = :fid')
            ->setParameter('fid', $facebook_id)
            ->setMaxResults(1);
        $result = $qb->getQuery()->getResult();

        //add to database if doesn't exists
        if ( !count($result) ) {
            $User = new User();
            $User->setCreatedAt(new \DateTime());
            $User->setNickname($nickname);
            $User->setRealname($realname);
            $User->setEmail($email);
            $User->setAvatar($avatar);
            $User->setFID($facebook_id);

            $em = $this->doctrine->getManager();
            $em->persist($User);
            $id = $em->flush();
        } else {
            $id = $result[0]['id'];
        }

        //set id
        $this->session->set('id', $id);

        //@TODO: hmm : is admin
        if ($this->isUserAdmin($nickname)) {
            $this->session->set('is_admin', true);
        }

        //parent:: returned value
        return $this->loadUserByUsername($response->getNickname());
    }

    public function supportsClass($class)
    {
        return $class === 'Acme\\DemoBundle\\Provider\\OAuthUser';
    }
}


#Acme\DemoBundle\Provider\OAuthUser
<?php

namespace Acme\DemoBundle\Provider;

use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUser as HWIOAuthUser;

class OAuthUser extends HWIOAuthUser{
    private $isAdmin = false;
    public function __construct($username, $isAdmin = false)
    {
        parent::__construct($username);
        $this->isAdmin = $isAdmin;
    }

    public function getRoles()
    {
        $roles = array('ROLE_USER', 'ROLE_OAUTH_USER');

        if ($this->isAdmin) {
            array_push($roles, 'ROLE_SUPER_ADMIN');
        }

        return $roles;
    }
}

因此,您几乎可以看到,当 facebook 登录响应出现时,我会进行数据库检查(基于 facebook 图 ID),并在需要时添加它。另外,我在会话中设置了一些东西(你不需要这个),之后我还必须返回一个 HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUser 对象(这是 sf2 获得它的角色的地方)。所以我扩展了它(通过这种方式我可以访问 $isAdmin)。正如您所说,您需要每个用户的角色,您还必须编辑它们。为此,您可以使用 ManyToMany 关系实现 getRoles() (通过构造函数访问学说 entityManager)。你可以在这里看到应用:http: //symfony.com/doc/current/cookbook/security/entity_provider.html#managing-roles-in-the-database

正如我所说,您必须对其进行大量调整(我唯一的应用程序是仅限 facebook 登录并具有类似安全访问的 in_memory),但我希望自己在开始时有这样的代码。所以我真的希望这对你有帮助。发布您的问题,如果有的话。

于 2013-08-17T15:38:50.820 回答