Я пытаюсь объединить FOSUserBundle и HWIOAuthBundle в следующих статьях, как https://gist.github.com/danvbe/4476697. Однако я не хочу автоматическую регистрацию новых пользователей, прошедших проверку подлинности OAuth2: пользователь должен предоставить дополнительную информацию.
Желаемый результат
Я хотел бы, например, следующую информацию для зарегистрированного пользователя:
Теперь, когда пользователь проходит проверку подлинности через Facebook и пользователь еще не существует, я хочу, чтобы в регистрационной форме заполнялась недостающая информация (отображаемое имя и изображение профиля). Только после этого должен быть создан новый FOSUser.
В большинстве учебных пособий такие поля, как изображение профиля и адрес электронной почты, автоматически заполняются информацией Facebook. Это не всегда желательно и не возможно.
Кроме того, подумайте о таких вещах, как принятие условий соглашения и правил, которые вы хотите показать, до создания пользователя.
Возможные подходы
Я думаю, что решением было бы создать новый вид AnonymousToken, OAuthenticatedToken, который содержит соответствующую информацию OAuth2, но не учитывает аутентификацию. Затем сделайте так, чтобы все страницы проверяли этот вид аутентификации и позволяли другим страницам перенаправлять на страницу регистрации OAuth. Тем не менее, это кажется мне излишне сложным решением.
Другим решением, вероятно, было бы написать код с нуля, а не использовать два упомянутых пакета. Я действительно надеюсь, что в этом нет необходимости.
Q: Как я могу вставить код завершения регистрации в остальную часть потока входа в систему?
(Я хотел бы поделиться некоторым кодом, но так как это та самая концепция, в которой мне нужна помощь, мне нечего показать.)
Редактировать: Решение
Следуя совету Дерика, я получил основы, работающие так:
Пользовательский провайдер пользователя сохраняет информацию (к сожалению, нет доступа к необработанному токену, поэтому я не могу войти в систему после регистрации):
class UserProvider extends FOSUBUserProvider {
protected $session;
public function __construct(Session $session, UserManagerInterface $userManager, array $properties) {
$this->session = $session;
parent::__construct( $userManager, $properties );
}
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
try {
return parent::loadUserByOAuthUserResponse($response);
}
catch ( AccountNotLinkedException $e ) {
$this->session->set( 'oauth.resource', $response->getResourceOwner()->getName() );
$this->session->set( 'oauth.id', $response->getResponse()['id'] );
throw $e;
}
}
}
Пользовательский обработчик ошибок:
<?php
// OAuthFailureHandler.php
class OAuthFailureHandler implements AuthenticationFailureHandlerInterface {
public function onAuthenticationFailure( Request $request, AuthenticationException $exception) {
if ( !$exception instanceof AccountNotLinkedException ) {
throw $exception;
}
return new RedirectResponse( 'fb-register' );
}
}
Оба зарегистрированы как сервис:
# services.yml
services:
app.userprovider:
class: AppBundle\Security\Core\User\UserProvider
arguments: [ "@session", "@fos_user.user_manager", {facebook: facebookID} ]
app.oauthfailurehandler:
class: AppBundle\Security\Handler\OAuthFailureHandler
arguments: ["@security.http_utils", {}, "@service_container"]
И настраивается в конфигурации безопасности:
# security.yml
security:
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
main:
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /login
check_path: /login_check
default_target_path: /profile
oauth:
login_path: /login
check_path: /login_check
resource_owners:
facebook: hwi_facebook_login
oauth_user_provider:
service: app.userprovider
failure_handler: app.oauthfailurehandler
anonymous: true
logout:
path: /logout
target: /login
В / fb-register я позволяю пользователю ввести имя пользователя и сохранить его самому:
/**
* @Route("/fb-register", name="hwi_oauth_register")
*/
public function registerOAuthAction(Request $request) {
$session = $request->getSession();
$resource = $session->get('oauth.resource');
if ( $resource !== 'facebook' ) {
return $this->redirectToRoute('home');
}
$userManager = $this->get('fos_user.user_manager');
$newUser = $userManager->createUser();
$form = $this->createForm(new RegisterOAuthFormType(), $newUser);
$form->handleRequest($request);
if ( $form->isValid() ) {
$newUser->setFacebookId( $session->get('oauth.id') );
$newUser->setEnabled(true);
$userManager->updateUser( $newUser );
try {
$this->container->get('hwi_oauth.user_checker')->checkPostAuth($newUser);
} catch (AccountStatusException $e) {
// Don't authenticate locked, disabled or expired users
return;
}
$session->remove('oauth.resource');
$session->remove('oauth.id');
$session->getFlashBag()
->add('success', 'You\'re succesfully registered!' );
return $this->redirectToRoute('home');
}
return $this->render( 'default/register-oauth.html.twig', array(
'form' => $form->createView()
) );
}
Пользователь не вошел в систему впоследствии, что очень плохо. Кроме того, нормальная функциональность fosub (редактирование профиля, изменение пароля) больше не работает из коробки.
Я просто использую имя пользователя в качестве отображаемого имени, не знаю, почему я этого раньше не видел.
Шаг 1:
Создайте своего собственного провайдера. Расширьте OAuthUserProvider и настройте его под свои нужды. Если пользователь успешно подключился, сгенерируйте конкретное исключение (вероятно, accountnotlinkedException) и отбросьте все соответствующие данные о входе в систему
Шаг 2:
Создайте свой собственный обработчик ошибок аутентификации. Убедитесь, что выбрасываемая ошибка является той, которую вы выдавали на шаге 1.
Здесь вы будете перенаправлены на страницу с дополнительной информацией.
Вот как зарегистрировать ваши пользовательские обработчики:
#security.yml
firewall:
main:
oauth:
success_handler: authentication_handler
failure_handler: social_auth_failure_handler
#user bundle services.yml (or some other project services.yml)
services:
authentication_handler:
class: ProjectName\UserBundle\Handler\AuthenticationHandler
arguments: ["@security.http_utils", {}, "@service_container"]
tags:
- { name: 'monolog.logger', channel: 'security' }
social_auth_failure_handler:
class: ProjectName\UserBundle\Handler\SocialAuthFailureHandler
arguments: ["@security.http_utils", {}, "@service_container"]
tags:
- { name: 'monolog.logger', channel: 'security' }
Шаг 3:
Создайте свою страницу дополнительной информации. Извлеките все соответствующие данные, которые вы сохранили на шаге 1, и создайте пользователя, если все получится.
Других решений пока нет …