如何使用Symfony4.3设置HWIOAuthBundle?

时间:2019-09-09 09:45:46

标签: symfony symfony4 hwioauthbundle

我在SF4.3上有项目,我不使用FOSUserBundle。如何设置HWIOAuthBundle?我现在拥有的配置:

security.yaml

main:
            anonymous: ~
            oauth:
                resource_owners:
                    facebook:           "/login/check-facebook"
                    google:             "/login/check-google"
                    #my_custom_provider: "/login/check-custom"
                    #my_github:          "/login/check-github"
                login_path:        /login
                use_forward:       false
                failure_path:      /login
                provider: users
                oauth_user_provider:
                    service: my.oauth_aware.user_provider.service

hwi_oauth.yaml

hwi_oauth:
    # list of names of the firewalls in which this bundle is active, this setting MUST be set
    firewall_names: [main]

    # https://github.com/hwi/HWIOAuthBundle/blob/master/Resources/doc/2-configuring_resource_owners.md
    resource_owners:
        facebook:
            type:                facebook
            client_id:           '%env(FB_ID)%'
            client_secret:       '%env(FB_SECRET)%'
            scope:               "email"
            options:
                display: popup
                csrf: true
        google:
            type:                google
            client_id:           '%env(G_ID)%'
            client_secret:       '%env(G_SECRET)%'
            scope:               "email"

和security.yaml

my.oauth_aware.user_provider.service:
    class: HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider
    arguments:
        - '@fos_user.user_manager'
        - ['@fos_user.user_manager', google: google ]

如果我不为security.yaml中的用户提供程序使用FOSUser,则必须不同,如何为我的User配置提供程序?

2 个答案:

答案 0 :(得分:1)

好的,我创建了自己的提供商:

dates = pd.date_range(start = '1-Sep-2017',end = '15-Sep-2017')

DatetimeIndex(['2017-09-01', '2017-09-02', '2017-09-03', '2017-09-04',
               '2017-09-05', '2017-09-06', '2017-09-07', '2017-09-08',
               '2017-09-09', '2017-09-10', '2017-09-11', '2017-09-12',
               '2017-09-13', '2017-09-14', '2017-09-15'],
              dtype='datetime64[ns]', freq='D')

在我的class OAuthUserProvider extends BaseClass { public $entityManager; public $userRepository; public function __construct( UserManagerInterface $userManager, array $properties, UserRepository $userRepository, EntityManagerInterface $entityManager ) { parent::__construct($userManager, $properties); $this->userRepository = $userRepository; $this->entityManager = $entityManager; } /** * {@inheritdoc} * @throws \Doctrine\ORM\NonUniqueResultException */ public function loadUserByOAuthUserResponse(UserResponseInterface $response) { $socialID = $response->getUsername(); $user = $this->userRepository->findByGoogleId($socialID); $email = $response->getEmail(); //check if the user already has the corresponding social account if (null === $user) { //check if the user has a normal account $user = $this->userRepository->findUserByEmail($email); if (null === $user || !$user instanceof UserInterface) { //if the user does not have a normal account, set it up: $user = new User(); $user->setEmail($email); $user->setPlainPassword(md5(uniqid('', true))); $user->setActive(true); } //then set its corresponding social id $service = $response->getResourceOwner()->getName(); switch ($service) { case 'google': $user->setGoogleID($socialID); break; case 'facebook': $user->setFacebookID($socialID); break; } $em = $this->entityManager; $em->persist($user); $em->flush(); //$this->userManager->updateUser($user); } else { //and then login the user $checker = new UserChecker(); $checker->checkPreAuth($user); } return $user; } } 中:

services.yaml

答案 1 :(得分:1)

如果要使用自定义的User类(例如App \ Entity \ User),解决方案是创建自己的用户提供程序。如果希望用户能够使用传统登录表单以及HWIOAuthBundle进行身份验证,则可以开始将自己的用户提供程序设置为described here。当然,您必须在这两种方法内添加一些代码,然后才能起作用(请参见下面的示例),并且不要忘记在 中设置 提供程序 security.yaml 就像这样:

    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            id: App\Security\UserProvider

然后,如果您可以通过新创建的用户提供程序使用传统的登录表单进行身份验证,并且一切正常,则可以开始集成HWIOAuthBundle。开始将 oauth_user_provider 设置定向到您自己的用户提供程序类。您的主防火墙可能看起来像这样:

    firewalls:
        main:
            anonymous: true
            oauth:
                resource_owners:
                    facebook: "/login/check-facebook"
                oauth_user_provider:
                    service: App\Security\UserProvider       # HERE YOU GO!
                login_path: /login
                use_forward:       false
                failure_path:      /login
            form_login:
                login_path: /login
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            logout:
                path: app_logout

通过这种方式应将App \ Security \ UserProvider类自动连接到服务容器中。如果不是,则必须手动将服务添加到您的service.yaml。

如果您现在尝试从HWIOAuthBundle用资源所有者(例如Facebook或Google)登录,则会收到错误消息,因为您的用户提供者类必须实现HWI的OAuthAwareUserProviderInterface。快速浏览该接口源文件将发现您必须向用户提供者添加一种方法:   loadUserByOAuthUserResponse(UserResponseInterface $ response)。因此,让您的User Provider类实现HWI OAuthAwareUserProviderInterface并将该方法添加到该类中。这非常简单。

这是我为此测试用例编写的完整的用户提供程序:

<?php

namespace App\Security;

use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Doctrine\ORM\EntityManagerInterface;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthAwareUserProviderInterface;
use App\Entity\User;

class UserProvider implements UserProviderInterface, OAuthAwareUserProviderInterface
{
    private $em;
    private $property = 'email';

    public function __construct(EntityManagerInterface $em) {
        $this->em = $em;
    }

    /**
     * @return UserInterface
     */
    public function loadUserByUsername($username)
    {
        $repository = $this->em->getRepository(User::class);

        if (null !== $this->property) {
            $user = $repository->findOneBy([$this->property => $username]);
        } else {
            if (!$repository instanceof UserLoaderInterface) {
                throw new \InvalidArgumentException(sprintf('You must either make the "%s" entity Doctrine Repository ("%s") implement "Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface" or set the "property" option in the corresponding entity provider configuration.', $this->classOrAlias, \get_class($repository)));
            }
            $user = $repository->loadUserByUsername($username);
        }

        if (null === $user) {
            throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
        }

        return $user;
    }

    /**
     * @return UserInterface
     */
    public function refreshUser(UserInterface $user)
    {
        if (!$user instanceof User) {
            throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', User::class));
        }

        $repository = $this->em->getRepository(User::class);

        if ($repository instanceof UserProviderInterface) {
            $refreshedUser = $repository->refreshUser($user);
        } else {
            $refreshedUser = $repository->find($user->getId());
            if (null === $refreshedUser) {
                throw new UsernameNotFoundException(sprintf('User with id %s not found', json_encode($user->getId())));
            }
        }

        return $refreshedUser;
    }

    /**
     * @return UserInterface
     */
    public function loadUserByOAuthUserResponse(UserResponseInterface $response)
    {
        return $this->loadUserByUsername($response->getEmail());
    }

    /**
     * Tells Symfony to use this provider for this User class.
     */
    public function supportsClass($class)
    {
        return User::class === $class;
    }
}

此用户提供程序尚未准备好。例如,如果未知的facebook / google / ...用户尝试登录,它将引发异常。您必须根据需要扩展此示例并对其进行全面测试!