个性化阅读
专注于IT技术分析

如何在Symfony 3中将FWUserBundle与HWIOAuthBundle一起配置和使用(社交登录)

本文概述

今天, 很多人都遭受着著名的”密码疲劳”的折磨, 甚至可能是你。网站的访问者一直在寻找一种做事的简单方法, 当我们谈论登录网站时, 社交登录是最好的选择, 因为用户可以使用他们现有的社交帐户, 例如Facebook, Google +, Twitter等。这种优势可以通过改善用户体验来提高你网站上的转化次数。许多网站报告说, 其目标消费者更喜欢使用社交登录, 而不是在其网站上创建新帐户, 这是有充分理由的。对于Symfony项目, HWIOAuthBundle是实现此任务的最著名和最佳解决方案。

在本文中, 你将学习如何允许你的用户使用社交网络登录到你的应用程序。尽管你可以用任何方式配置任何社交网络, 但在这种情况下, 我们将通过Github, Facebook, Google Plus和Stack Exchange进行说明。

注意

如果要添加其他社交网络(如Twitter等), 则可以遵循相同的过程。或者, 如果你不需要示例中的社交网络, 则跳过该步骤。

要求

在继续之前, 你需要为要添加的每个社交网络(资源所有者)在数据库的fos_user表中创建2个字符串类型(Varchar 255)类型的列。我们将这一步骤作为一项要求, 因为你是决定如何将字段添加到数据库的人。一些开发人员使用诸如PHPMyAdmin之类的管理器来处理数据库, 或者通过修改user.orm.yml文件, 然后使用php bin / console doctrine:schema:update –force来构建数据库, 从而遵循symfony的方式。

每个资源所有者的2个字段均遵循下一个命名法:<社交网络名称> _id和<社交网络名称> _access_token。例如, 对于我们提到的4个社交网络, 在fos_user表中将有8个新列, 即:

github_id
github_access_token

facebook
facebook_access_token

googleplus_id
googleplus_access_token

stackexchange_id
stackexchange_access_token

一旦这些列存在, 你显然需要在应用程序的User类中添加该字段的getter和setter:

/** @ORM\Column(name="github_id", type="string", length=255, nullable=true) */
protected $github_id;

/** @ORM\Column(name="github_access_token", type="string", length=255, nullable=true) */
protected $github_access_token;

/** @ORM\Column(name="facebook_id", type="string", length=255, nullable=true) */
protected $facebook_id;

/** @ORM\Column(name="facebook_access_token", type="string", length=255, nullable=true) */
protected $facebook_access_token;

/** @ORM\Column(name="googleplus_id", type="string", length=255, nullable=true) */
protected $googleplus_id;

/** @ORM\Column(name="googleplus_access_token", type="string", length=255, nullable=true) */
protected $googleplus_access_token;

/** @ORM\Column(name="stackexchange_id", type="string", length=255, nullable=true) */
protected $stackexchange_id;

/** @ORM\Column(name="stackexchange_access_token", type="string", length=255, nullable=true) */
protected $stackexchange_access_token;

public function setGithubId($githubId) {
    $this->github_id = $githubId;

    return $this;
}

public function getGithubId() {
    return $this->github_id;
}

public function setGithubAccessToken($githubAccessToken) {
    $this->github_access_token = $githubAccessToken;

    return $this;
}

public function getGithubAccessToken() {
    return $this->github_access_token;
}

public function setFacebookId($facebookID) {
    $this->facebook_id = $facebookID;

    return $this;
}

public function getFacebookId() {
    return $this->facebook_id;
}

public function setFacebookAccessToken($facebookAccessToken) {
    $this->facebook_access_token = $facebookAccessToken;

    return $this;
}

public function getFacebookAccessToken() {
    return $this->facebook_access_token;
}

public function setGoogleplusId($googlePlusId) {
    $this->googleplus_id = $googlePlusId;

    return $this;
}

public function getGoogleplusId() {
    return $this->googleplus_id;
}

public function setGoogleplusAccessToken($googleplusAccessToken) {
    $this->googleplus_access_token = $googleplusAccessToken;

    return $this;
}

public function getGoogleplusAccessToken() {
    return $this->googleplus_access_token;
}


public function setStackexchangeId($stackExchangeId) {
    $this->stackexchange_id = $stackExchangeId;

    return $this;
}

public function getStackexchangeId() {
    return $this->stackexchange_id;
}

public function setStackexchangeAccessToken($stackExchangeAccessToken) {
    $this->stackexchange_access_token = $stackExchangeAccessToken;

    return $this;
}

public function getStackexchangeAccessToken() {
    return $this->stackexchange_access_token;
}

如果按顺序设置了所有内容, 则可以从User对象检索这些属性, 然后可以继续配置HWIOAuthBundle。

注意

请记住, 在修改用户类时, 你需要清除当前用户的缓存并注销, 否则当你添加新字段时, 直到用户再次登录后, 它们才会更新。

1.安装并启用HWIOAuthBundle

首先, 你需要使用以下命令通过composer安装HWIOAuthBundle:

composer require hwi/oauth-bundle

另外, 你可以手动修改composer.json并将捆绑包设置为依赖项:

{
    "require": {
        "hwi/oauth-bundle": "^0.5.3", }
}

最后使用composer install进行安装。捆绑软件安装完成后, 请不要忘记在symfony应用程序的AppKernel.php文件中启用它:

<?php

use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            // .. 
            new HWI\Bundle\OAuthBundle\HWIOAuthBundle(), // .. 
        ];

        // .. 
    }
}

2.在社交网络上创建开发者帐户

允许用户使用社交网络登录应用程序的最重要一点是, 第三方服务(社交网络)也允许你执行此操作。为此, 大多数服务都需要注册你的应用程序才能管理请求权限等。

例如, 对于Github, 你可以在这里注册你的应用程序, 在这里注册Facebook, 在这里注册Stack Exchange, 在这里注册Google Plus。注册你的应用程序后, 他们将为你提供所需的OAuth令牌, 这些令牌将使你可以向其服务器创建请求。 Github管理器看起来像:

OAuth Manager Github

注意

除了自定义应用程序的设置外, 你还需要提供我们将在步骤4中定义的授权回调URL。因此, 使用此选项将你的应用程序创建为空, 并且在完成本教程后不要忘记对其进行更新。

在这种情况下, URL将遵循https:// yourwebsite / connect / check- <resource-owner-name>之类的模式。但是, 在遵循本教程的过程中, 你可以自由更改回调URL。

几乎所有的资源所有者都有至少两个参数, 即client_id和secret。在此示例中, 我们将使用前面提到的4个社交网络, 因此我们需要在app / config / config.yml文件中注册以下参数。建议你也将令牌存储在双引号中, 例如”在此处输入你的令牌”:

# app/config/config.yml
parameters:
    # For Github you'll need the client_id and secret   
    github_client_id: <replace-with-your-github-client-id>
    github_secret: <replace-with-your-github-secret>
    
    # For Facebook you'll need the client_id and secret   
    facebook_client_id: <replace-with-your-facebook-client-id>
    facebook_secret: <replace-with-your-facebook-secret>
    
    # For Google+ you'll need the client_id and secret   
    googleplus_client_id: <replace-with-your-googleplus-client-id>
    googleplus_secret: <replace-with-your-googleplus-secret>
    
    # For Stack Exchange you'll need the client_id, secret and key
    stackexchange_client_id: <replace-with-your-stackexchange-client-id>
    stackexchange_secret: <replace-with-your-stackexchange-secret>
    stackexchange_key: <replace-with-your-stackexchange-key>

这些令牌将由资源所有者在下一步中使用。

3.配置HWIO和资源所有者

既然你有权创建对所需社交网络服务器的请求, 则需要创建每个社交网络的本地资源所有者。转到Symfony应用程序的config.yml文件, 然后设置HWIOAuthBundle的配置(hwi_oauth)。在这里, 你可以使用各自的访问令牌注册新的社交网络:

# app/config/config.yml
hwi_oauth:
    # Define which firewalls will be used for oauth
    # Usually, its only the main, but you can add it if you have a custom one
    firewall_names: ["main"]
    fosub:
        username_iterations: 30
        # Define in which columns of the fos_user table will be stored
        # the access token of every resource_owner
        properties:
            github: github_id
            facebook: facebook_id
            googleplus: googleplus_id
            stackexchange: stackexchange_id
    # Define the resource_owners that your user can use to login into your app
    # Note that the client_id and client_secret and key values are symfony parameters
    # stored too in the config.yml from the previous step !
    resource_owners:
        github:
            type:           github
            client_id:      "%github_client_id%"
            client_secret:  "%github_secret%"
            scope: 'user:email, public_repo'
        facebook:
            type:           facebook
            client_id:      "%facebook_client_id%"
            client_secret:  "%facebook_secret%"
            infos_url:     "https://graph.facebook.com/me?fields=id, name, email"
        googleplus:
            type:           google
            client_id:      "%googleplus_client_id%"
            client_secret:  "%googleplus_secret%"
            scope:  "email profile"
        stackexchange:
            type:           stack_exchange
            client_id:      "%stackexchange_client_id%"
            client_secret:  "%stackexchange_secret%"
            options:
                key: "%stackexchange_key%"

有关每个资源所有者的配置如何工作的更多信息, 请在此处参考HWIOAuthBundle的官方文档。

4.配置资源所有者路由

你的用户将需要访问标识他要登录的社交网络的路由。转到应用程序的app / config / security.yml文件, 并为防火墙添加oauth配置:

# app/config/security.yml
security:
    # Modify firewalls
    firewalls:
        # Set the config on your firewall
        main:
            oauth:
                # Declare the OAuth Callback URLs for every resource owner
                # They will be added in the routing.yml file too later
                resource_owners:
                    github: "/connect/check-github"
                    facebook: "/connect/check-facebook"
                    googleplus: "/connect/check-googleplus"
                    stackexchange: "/connect/check-stackexchange"
                ## Provide the original login path of your application (fosuserroute)
                ## and the failure route when the authentication fails.
                login_path:     /user/login
                failure_path:   /user/login
                # Inject a service that will be created in the step #6
                oauth_user_provider:
                    service: app.fos_user.oauth_provider

接下来, 继续将HWIOBundle和资源所有者的路由添加到你的app / config / routing.yml文件中:

注意

如第2步所述, 在Facebook, Github等应用程序的OAuth帐户管理器中, 你需要提供OAuth回调URL。你可以使用此步骤的路由来提供到第三方服务的路由, 例如http://yoursite.com/connect/check-facebook。

# app/config/routing.yml

hwi_oauth_redirect:
    resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
    prefix:   /connect
    
hwi_oauth_connect:
    resource: "@HWIOAuthBundle/Resources/config/routing/connect.xml"
    prefix:   /connect

hwi_oauth_login:
    resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
    prefix:   /login
    
github_login:
    path: /connect/check-github
    
facebook_login:
    path: /connect/check-facebook
    
googleplus_login:
    path: /connect/check-googleplus

stackexchange_login:
    path: /connect/check-stackexchange

这样, 如果用户想使用其Facebook帐户登录到你的应用程序, 则只需要将其重定向到http://yoursite.com/connect/check-facebook路由。

5.创建登录和注册管理器

在某种程度上, 你的应用程序需要从社交网络接收信息以进行注册或登录。这就是下面的FOSUBUserProvider类的功能。默认情况下, 它不需要任何修改即可工作。用户访问检查路由后, loadUserByOAuthUserResponse函数将生效。如果用户未在你的应用程序上的社交网络帐户中注册, 则默认情况下, 它将在fos_user表上使用随机用户名(例如12345_ <name-of-social-network>)创建新行并自动对其进行签名。如果用户已经存在, 它将通过<social-network> _id字段搜索用户, 并将发送访问令牌以检索信息。

你可以随意修改类以设置所需的字段, 设置所需的用户名等。在这种情况下, 我们将类存储在AppBundle的Entity文件夹中, 但你可以将其保存在任何位置:

<?php

// Change the namespace according to your project.
namespace AppBundle\Entity;

use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseClass;
use Symfony\Component\Security\Core\User\UserInterface;


// Source: https://gist.github.com/danvbe/4476697

class FOSUBUserProvider extends BaseClass {

    public function connect(UserInterface $user, UserResponseInterface $response) {
        $property = $this->getProperty($response);
        
        $username = $response->getUsername();
        
        // On connect, retrieve the access token and the user id
        $service = $response->getResourceOwner()->getName();
        
        $setter = 'set' . ucfirst($service);
        $setter_id = $setter . 'Id';
        $setter_token = $setter . 'AccessToken';
        
        // Disconnect previously connected users
        if (null !== $previousUser = $this->userManager->findUserBy(array($property => $username))) {
            $previousUser->$setter_id(null);
            $previousUser->$setter_token(null);
            $this->userManager->updateUser($previousUser);
        }
        
        // Connect using the current user
        $user->$setter_id($username);
        $user->$setter_token($response->getAccessToken());
        $this->userManager->updateUser($user);
    }

    public function loadUserByOAuthUserResponse(UserResponseInterface $response) {
        $data = $response->getResponse();
        $username = $response->getUsername();
        $email = $response->getEmail() ? $response->getEmail() : $username;
        $user = $this->userManager->findUserBy(array($this->getProperty($response) => $username));
        
        // If the user is new
        if (null === $user) {
            $service = $response->getResourceOwner()->getName();
            $setter = 'set' . ucfirst($service);
            $setter_id = $setter . 'Id';
            $setter_token = $setter . 'AccessToken';
            // create new user here
            $user = $this->userManager->createUser();
            $user->$setter_id($username);
            $user->$setter_token($response->getAccessToken());
            
            //I have set all requested data with the user's username
            //modify here with relevant data
            $user->setUsername($this->generateRandomUsername($username, $response->getResourceOwner()->getName()));
            $user->setEmail($email);
            $user->setPassword($username);
            $user->setEnabled(true);
            $this->userManager->updateUser($user);
            return $user;
        }
        
        // If the user exists, use the HWIOAuth
        $user = parent::loadUserByOAuthUserResponse($response);
        
        $serviceName = $response->getResourceOwner()->getName();
        
        $setter = 'set' . ucfirst($serviceName) . 'AccessToken';
        
        // Update the access token
        $user->$setter($response->getAccessToken());
        
        return $user;
    }
    
    /**
     * Generates a random username with the given 
     * e.g 12345_github, 12345_facebook
     * 
     * @param string $username
     * @param type $serviceName
     * @return type
     */
    private function generateRandomUsername($username, $serviceName){
        if(!$username){
            $username = "user". uniqid((rand()), true) . $serviceName;
        }
        
        return $username. "_" . $serviceName;
    }
}

6.创建fos_user.oauth_provider服务

在security.yml中, 我们使用app.fos_user.oauth_provider服务定义了oauth_user_provider选项, 该选项到现在还不存在, 因此你需要创建它。该服务返回FOSUBUserProvider类, 并将FOSUserBundle的用户管理器和在步骤3中创建的资源所有者作为参数:

# app/config/services.yml
services:
    app.fos_user.oauth_provider:
        # Change the class according to the location of the FOSUBUserProvider class
        class: AppBundle\Entity\FOSUBUserProvider
        arguments:
            # Inject as first argument the user_manager of FOSUserBundle
            user_manager: "@fos_user.user_manager"
            # An object/array with the registered Social Media from config.yml
            user_response:
                github: github_id
                facebook: facebook_id
                googleplus: googleplus_id 
                stackexchange: stackexchange_id

7.测试!

如果一切均已正确配置(并遵循默认配置), 则可以通过社交网络访问(登录或注册)以下路径:

<!-- Remove app_dev.php from the URL if you aren't in DEV mode -->

<a href="/app_dev.php/connect/github">
    Login with Github 
</a>

<a href="/app_dev.php/connect/stackexchange">
    Login with Stack Exchange 
</a>

<a href="/app_dev.php/connect/facebook">
    Login with Facebook 
</a>

<a href="/app_dev.php/connect/googleplus">
    Login with Google+ 
</a>

在这里, 用户将被重定向到”社交网络”授予页面, 该页面询问用户是否真的要使用其帐户登录另一个应用程序。值得一提的是, 你需要清除缓存并从当前帐户注销, 以防止出现任何错误。

编码愉快!

赞(0)
未经允许不得转载:srcmini » 如何在Symfony 3中将FWUserBundle与HWIOAuthBundle一起配置和使用(社交登录)

评论 抢沙发

评论前必须登录!