Symfony2 : How to login using OAuth (HWIOAuthBundle) + custom roles (by default and loaded from DB)

标签 symfony doctrine-orm roles hwioauthbundle

Note: the questions are at the end of this text but I will explain in detail all the context for a better understanding.

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

  1. Module for students -> Needs the role ROLE_STUDENT
  2. Module for teachers -> Needs the role ROLE_TEACHER
  3. Module for administrators -> Needs the role ROLE_ADMIN

角色层次结构如下:

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

因此:

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

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

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

The system uses OAuth to authenticate students and teachers through Twitter, using the bundle HWIOAuthBundle (using the OAuthUserProvider user provider that provides the bundle).

I've achieved to successfully authenticate users but, by default, all users are automatically authenticated with the following roles: [ROLE_USER, ROLE_OAUTH_USER]

<小时/>

这就是我所做的。下面,我将解释我希望我的应用程序做什么,但我不知道方法:

Steps for login using OAuth:

A user logs in to the system and automatically:

  • If the user does not exist in the database:
    - Save the nickname in the users table of the database.
    - Save the role ROLE_STUDENT (this is the role by default for me) in the users table of the database.
    - Authenticate in the system using OAuth but using the ROLE_STUDENT role.

  • If the user exists in the database:
    - Check what role has associated the user in the database.
    - Authenticate the user in the system using OAuth but using the role associated in the database (i.e.: ROLE_STUDENT or ROLE_TEACHER).

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

<小时/>

问题:

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

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

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

提前谢谢您!

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

最佳答案

更新:

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

<小时/>

我有一周的 symfony2 经验,在过去的几天里,我自己就是这么做的。今天发现你的问题(当我还在研究时)。

我将向您展示我必须做什么、基于哪些数据以及我是如何做的。之后,我将尝试为您提供一些关键链接,希望您能够根据您的需求进行建模。

我的应用程序需要 Facebook 登录和 ADMIN 角色。因为只有几个管理员,所以我在身份验证时只需要几个 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),并在需要时添加它。另外,我在 session 中设置了一些东西(你不需要这个),之后我还必须返回一个 HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUser 对象(这是 sf2 获取其角色的地方)。所以我扩展了它(这样我就可以访问 $isAdmin)。正如您所说,您需要每个用户的角色,并且还必须编辑它们。为此,您可以使用 ManyToMany 关系实现 getRoles() (通过构造函数授予对原则实体管理器的访问权限)。您可以在此处看到应用:http://symfony.com/doc/current/cookbook/security/entity_provider.html#managing-roles-in-the-database .

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

关于Symfony2 : How to login using OAuth (HWIOAuthBundle) + custom roles (by default and loaded from DB),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18264800/

相关文章:

Symfony2 findBy 方法,具有关系中的属性

asp.net-mvc - ASP.NET MVC - 动态授权

php - Symfony 2 中 Zend\Validate\Db\NoRecordExists 的模拟

Symfony 3.3.2 Doctrine EntityRepository 构造函数参数

MySQL/Doctrine : allowing null fields on insert, 但未更新

php - 我应该使用 EAV 模型吗?

reactjs - 如果在 HTML 元素上设置 role = ""会发生什么?

asp.net - 向 Web.config 中创建的用户添加角色

Symfony2 <a> 链接 'post' 或 'delete' 或 'put' 方法

deployment - 在 Symfony 2 中将应用程序移至生产模式