EC-CUBE4でYahoo!ID連携を実装する方法です。
細かい説明はしていませんのでご了承ください。
ファイル設置場所やファイル名はネームスペースやクラス名をご確認ください。
必要なライブラリをComposerでインストール
bin/console eccube:composer:require knpuniversity/oauth2-client-bundle:1.4 bin/console eccube:composer:require tavii/oauth2-yconnect
bundles.phpにライブラリを追加
<?php // app/config/eccube/bundles.php /* * This file is part of EC-CUBE * * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved. * * http://www.ec-cube.co.jp/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ return [ // ... KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class => ['all' => true] ];
knpu_oauth2_client.yamlを追加
YahooJapan!デベロッパーネットワークのアプリケーションの管理にてClient IDとシークレットを取得して設定してください。
knpu_oauth2_client: clients: yconnect_client: type: generic provider_class: Customize\Security\OAuth2\Client\Provider\YConnect client_id: ***************************************** client_secret: ************************************* redirect_route: yahoo_callback
インストールしたoauth2-yconnectを若干修正
<?php namespace Customize\Security\OAuth2\Client\Provider; class YConnect extends \Tavii\OAuth2\Client\Provider\YConnect { const YAHOO_LOGIN_USERINFO = 'yahoo_login.userinfo'; public $version = 'v2'; }
Customerエンティティにyahoo_user_idプロパティを追加
<?php namespace Customize\Entity; use Customize\Entity\Master\CustomerType; use Doctrine\ORM\Mapping as ORM; use Eccube\Annotation\EntityExtension; /** * @EntityExtension("Eccube\Entity\Customer") */ trait CustomerTrait { /** * @ORM\Column(type="string", length=255, nullable=true) */ private $yahoo_user_id; public function getYahooUserId(): ?string { return $this->yahoo_user_id; } public function setYahooUserId(?string $yahoo_user_id): self { $this->yahoo_user_id = $yahoo_user_id; return $this; } }
YahooAuthenticatorを用意
<?php namespace Customize\Security\Authenticator; use Customize\Security\OAuth2\Client\Provider\YConnect; use Doctrine\ORM\EntityManagerInterface; use Eccube\Entity\Customer; use KnpU\OAuth2ClientBundle\Client\ClientRegistry; use KnpU\OAuth2ClientBundle\Exception\InvalidStateException; use KnpU\OAuth2ClientBundle\Security\Authenticator\SocialAuthenticator; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\UserProviderInterface; class YahooAuthenticator extends SocialAuthenticator { /** * @var ClientRegistry */ private $clientRegistry; /** * @var EntityManagerInterface */ private $entityManager; /** * @var RouterInterface */ private $router; /** * @var SessionInterface */ private $session; public function __construct( ClientRegistry $clientRegistry, EntityManagerInterface $entityManager, RouterInterface $router, SessionInterface $session ) { $this->clientRegistry = $clientRegistry; $this->entityManager = $entityManager; $this->router = $router; $this->session = $session; } public function supports(Request $request) { return $request->attributes->get('_route') === 'yahoo_callback'; } /** * @inheritDoc */ public function start(Request $request, AuthenticationException $authException = null) { return new RedirectResponse( $this->router->generate("yahoo"), Response::HTTP_TEMPORARY_REDIRECT ); } /** * @inheritDoc */ public function getCredentials(Request $request) { try { return $this->fetchAccessToken($this->getYahooClient()); } catch (InvalidStateException $e) { return false; } } /** * @inheritDoc */ public function getUser($credentials, UserProviderInterface $userProvider) { // stateが正しくない時がある if ($credentials) { $userInfo = $this->getYahooClient() ->fetchUserFromToken($credentials); } else { return null; } // メールアドレス認証していない場合がある if(!$userInfo->getEmailVerified()) { return null; } // ヤフー連携済みの場合 $Customer = $this->entityManager->getRepository(Customer::class) ->findOneBy(['yahoo_user_id' => $userInfo->getSub()]); if ($Customer) { return $Customer; } $Customer = $this->entityManager->getRepository(Customer::class) ->findOneBy(['email' => $userInfo->getEmail()]); // 会員登録していない場合、会員登録ページへ if (!$Customer) { $this->session->set(YConnect::YAHOO_LOGIN_USERINFO, $userInfo->toArray()); return null; } // 通常の会員登録済みの場合はユーザー識別子を保存 $Customer->setYahooUserId($userInfo->getSub()); $this->entityManager->persist($Customer); $this->entityManager->flush(); return $Customer; } /** * @inheritDoc */ public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { $message = strtr($exception->getMessageKey(), $exception->getMessageData()); if ($this->session->get(YConnect::YAHOO_LOGIN_USERINFO)) { return new RedirectResponse($this->router->generate("entry")); } else { return new RedirectResponse($this->router->generate("yahoo")); } } /** * @inheritDoc */ public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) { $targetUrl = $this->router->generate("mypage"); return new RedirectResponse($targetUrl); } private function getYahooClient() { return $this->clientRegistry ->getClient('yconnect_client'); } }
security.yamlを修正
guardを追加しています。
security: encoders: # Our user class and the algorithm we'll use to encode passwords # https://symfony.com/doc/current/security.html#c-encoding-the-user-s-password Eccube\Entity\Member: id: Eccube\Security\Core\Encoder\PasswordEncoder Eccube\Entity\Customer: id: Eccube\Security\Core\Encoder\PasswordEncoder providers: # https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded # In this example, users are stored via Doctrine in the database # To see the users at src/App/DataFixtures/ORM/LoadFixtures.php # To load users from somewhere else: https://symfony.com/doc/current/security/custom_provider.html member_provider: id: Eccube\Security\Core\User\MemberProvider customer_provider: id: Eccube\Security\Core\User\CustomerProvider # https://symfony.com/doc/current/security.html#initial-security-yml-setup-authentication firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false admin: pattern: '^/%eccube_admin_route%/' anonymous: true provider: member_provider form_login: check_path: admin_login login_path: admin_login csrf_token_generator: security.csrf.token_manager default_target_path: admin_homepage username_parameter: 'login_id' password_parameter: 'password' use_forward: true success_handler: eccube.security.success_handler failure_handler: eccube.security.failure_handler logout: path: admin_logout target: admin_login customer: pattern: ^/ anonymous: true provider: customer_provider remember_me: secret: '%kernel.secret%' lifetime: 3600 name: eccube_remember_me remember_me_parameter: 'login_memory' form_login: check_path: mypage_login login_path: mypage_login csrf_token_generator: security.csrf.token_manager default_target_path: homepage username_parameter: 'login_email' password_parameter: 'login_pass' use_forward: true success_handler: eccube.security.success_handler failure_handler: eccube.security.failure_handler logout: path: logout target: homepage guard: authenticators: - Customize\Security\Authenticator\YahooAuthenticator access_decision_manager: strategy: unanimous allow_if_all_abstain: false
Yahoo!ID連携用のコントローラーを用意
<?php namespace Customize\Controller; use Customize\OAuth2\Client\Provider\YConnect; use Eccube\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; /** * @Route("/yahoo") * * Class YahooController * @package Customize\Controller */ class YahooController extends AbstractController { /** * @var TokenStorageInterface */ private $tokenStorage; public function __construct( TokenStorageInterface $tokenStorage ) { $this->tokenStorage = $tokenStorage; } /** * @Route("/", name="yahoo") * * @return \Symfony\Component\HttpFoundation\RedirectResponse */ public function index() { return $this->get('oauth2.registry') ->getClient('yconnect_client') ->redirect([ "scope" => "openid profile email address" ]); } /** * @Route("/callback", name="yahoo_callback") */ public function callback() { if($this->isGranted("IS_AUTHENTICATED_FULLY")) { return $this->redirectToRoute("mypage"); }else{ return $this->redirectToRoute("yahoo"); } } }
EntryTypeを拡張
Yahoo!ID連携経由で会員登録する場合はyahoo_user_idを登録するためEntryTypeを拡張します。
<?php namespace Customize\Form\Extension; use Customize\Entity\Master\CustomerType; use Customize\Security\OAuth2\Client\Provider\YConnect; use Customize\Repository\Master\CustomerTypeRepository; use Eccube\Entity\Customer; use Eccube\Form\Type\AddressType; use Eccube\Form\Type\Front\EntryType; use Eccube\Form\Type\NameType; use Eccube\Form\Type\PostalType; use Eccube\Form\Type\RepeatedEmailType; use Eccube\Repository\Master\PrefRepository; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\HttpFoundation\Session\SessionInterface; class EntryTypeExtension extends AbstractTypeExtension { /** * @var SessionInterface */ private $session; /** * @var CustomerTypeRepository */ private $customerTypeRepository; /** * @var PrefRepository */ private $prefRepository; public function __construct( SessionInterface $session, CustomerTypeRepository $customerTypeRepository, PrefRepository $prefRepository ) { $this->session = $session; $this->customerTypeRepository = $customerTypeRepository; $this->prefRepository = $prefRepository; } public function buildForm(FormBuilderInterface $builder, array $options) { $userInfo = $this->session->get(YConnect::YAHOO_LOGIN_USERINFO); if($userInfo) { // 名前セット $options = $builder->get('name')->getOptions(); $options['lastname_options']['data'] = isset($userInfo["family_name"]) ? $userInfo["family_name"] : ""; $options['firstname_options']['data'] = isset($userInfo["given_name"]) ? $userInfo["given_name"] : ""; $builder->add('name', NameType::class, $options); // 郵便番号セット $options = $builder->get('postal_code')->getOptions(); $options['data'] = isset($userInfo["address"]["postal_code"]) ? $userInfo["address"]["postal_code"] : ""; $builder->add('postal_code', PostalType::class, $options); // 住所セット $options = $builder->get('address')->getOptions(); if(isset($userInfo["address"]["region"])) { $Pref = $this->prefRepository->findOneBy(["name" => $userInfo["address"]["region"]]); $options["pref_options"]["data"] = $Pref; } $options["addr01_options"]["data"] = isset($userInfo["address"]["locality"]) ? $userInfo["address"]["locality"] : ""; $builder->add('address', AddressType::class, $options); // メールアドレスセット $options = $builder->get('email')->getOptions(); $options["first_options"]['data'] = $userInfo["email"]; $options["second_options"]['data'] = $userInfo["email"]; $builder->add('email', RepeatedEmailType::class, $options); $builder ->add('yahoo_user_id', HiddenType::class, [ "data" => $userInfo["sub"], "eccube_form_options" => [ "auto_render" => true, 'form_theme' => "Form/Entry/hidden_type.html.twig" ] ]); } } /** * {@inheritdoc} */ public function getExtendedType() { return EntryType::class; } }
yahoo_user_id項目をHiddenにしたいのでテンプレートを用意
Form/Entry/hidden_type.html.twig
{% block form_row %} {{ form_widget(form) }} {{ form_errors(form) }} {% endblock %}
以上で完成のはずです。
Facebookログインなども上記を参考に修正すれば実装できるとかと思います。
投稿 【EC-CUBE4】Yahoo!ID連携を実装する方法 は あずみ.net に最初に表示されました。