Symfony2: как войти в систему с помощью OAuth (HWIOAuthBundle) + пользовательские роли (по умолчанию и загружены из БД)

Примечание: вопросы находятся в конце этого текста, но я подробно объясню весь контекст для лучшего понимания.

Я разрабатываю приложение Symfony2, состоящее из 3 модулей:

  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 user provider, который предоставляет пакет).

Я добился успешной аутентификации пользователей, но,по умолчанию, все пользователи автоматически аутентифицируются с следующие роли: [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: Если у вас есть какие-либо вопросы или сомнения, я буду рад объяснить как можно лучше.

1 ответов


обновление:

Я пытался использовать этот код в один из моих последних проектов, и он больше не работал. Причина в том, что HWIOAuthBundle обновился несколько раз, и файлы конфигурации не совпадают. Я поставил код выше, а также войти в несколько других социальных сетей в github, который вы можете найти в HWIOAuthBundleByExample.


У меня есть недельный опыт работы с symfony2, и в последние дни это то, что я сам работал. Найдено ваш вопрос сегодня (когда я еще изучаю).

мое приложение нуждается в Facebook логин и роль администратора. Потому что будет только несколько администраторов, мне нужно всего лишь несколько идентификаторов Facebook, когда authentificating, поэтому я храню их в массив и 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) и добавляю его при необходимости. Кроме того, я устанавливаю некоторые вещи в сеансах (вам это не понадобится), и после этого я должен также вернуть объект HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUser (здесь sf2 получает свои роли). Поэтому я расширяю его (таким образом, у меня есть доступ к $isAdmin). Как вы сказали, вам нужно роли для каждого пользователя, и вы также должны изменить их. Для этого вы можете реализовать getRoles() с отношением ManyToMany (предоставить доступ к doctrine entityManager через конструктор). Вы можете увидеть, что применяется здесь: http://symfony.com/doc/current/cookbook/security/entity_provider.html#managing-roles-in-the-database .

Как я уже сказал, Вы должны настроить его много (мое единственное приложение-только вход в facebook и с in_memory, как доступ к безопасности), но я хотел бы, чтобы у меня был код, как тогда я и начал. Так что я очень надеюсь, что это поможет тебе. Отправьте свои вопросы, если они есть.