我正在尝试将FOSUserBundle和HWIOAuthBundle结合起来,如 https://gist.github.com/danvbe/4476697。但是,我不希望自动注册经过 OAuth2 身份验证的新用户:用户应提供其他信息。
期望的结果
例如,我想要注册用户的以下信息:
- (用户名,虽然我宁愿只使用电子邮件)
- 显示名称(必填)
- 个人资料图片(必填)
- 电子邮件地址(如果没有Facebook-id,则需要) 密码
- (如果没有Facebook-id,则需要密码)
- Facebook-ID(如果没有电子邮件地址,则需要)
现在,当用户通过Facebook进行身份验证并且该用户尚不存在时,我想要一个注册表来填写缺少的信息(显示名称和个人资料图片)。只有在此之后,才应该创建新的 FOSUser。在大多数教程中,个人资料图片和电子邮件地址等字段会自动填充 Facebook 信息。这并不总是可取的,也不可能。
此外,请考虑接受协议条款和您希望在创建用户之前显示的规则。
可能的办法
我认为,一个解决方案是创建一种新的匿名令牌,即OAuthenticatedToken,它包含相关的OAuth2信息,但不计算身份验证。然后,让所有页面检查这种身份验证,并让其他页面重定向到 OAuth 注册页面。但是,这对我来说似乎是一个不必要的复杂解决方案。
另一种解决方案可能是从头开始编写代码,而不是使用提到的两个捆绑包。我真的希望这不是必需的。
问:如何在登录流程的其余部分插入注册完成代码?
(我很想分享一些代码,但由于这是我需要帮助的概念,所以我没有太多要展示的内容。
编辑:解决方案
在 Derick 的 adivce 之后,我得到了这样的基本工作:
自定义用户提供程序保存了信息(遗憾的是,无法访问原始令牌,因此我在注册后还无法登录用户):
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 中存储的所有相关数据,并在所有内容都签出时创建用户。