我正在使用HWIOAuthBundle让用户使用Oauth登录,我创建了一个自定义用户提供程序,以便在用户不存在时创建用户:
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$attr = $response->getResponse();
switch($response->getResourceOwner()->getName()) {
case 'google':
if(!$user = $this->userRepository->findOneByGoogleId($attr['id'])) {
if(($user = $this->userRepository->findOneByEmail($attr['email'])) && $attr['verified_email']) {
$user->setGoogleId($attr['id']);
if(!$user->getFirstname()) {
$user->setFirstname($attr['given_name']);
}
if(!$user->getLastname()) {
$user->setLastname($attr['family_name']);
}
$user->setGoogleName($attr['name']);
}else{
$user = new User();
$user->setUsername($this->userRepository->createUsernameByEmail($attr['email']));
$user->setEmail($attr['email']);
$user->setFirstname($attr['given_name']);
$user->setLastname($attr['family_name']);
$user->setPassword('');
$user->setIsActive(true);
$user->setGoogleId($attr['id']);
$user->setGoogleName($attr['name']);
$user->addGroup($this->groupRepository->findOneByRole('ROLE_USER'));
$this->entityManager->persist($user);
}
}
break;
case 'facebook':
if(!$user = $this->userRepository->findOneByFacebookId($attr['id'])) {
if(($user = $this->userRepository->findOneByEmail($attr['email'])) && $attr['verified']) {
$user->setFacebookId($attr['id']);
if(!$user->getFirstname()) {
$user->setFirstname($attr['first_name']);
}
if(!$user->getLastname()) {
$user->setLastname($attr['last_name']);
}
$user->setFacebookUsername($attr['username']);
}else{
$user = new User();
$user->setUsername($this->userRepository->createUsernameByEmail($attr['email']));
$user->setEmail($attr['email']);
$user->setFirstname($attr['first_name']);
$user->setLastname($attr['last_name']);
$user->setPassword('');
$user->setIsActive(true);
$user->setFacebookId($attr['id']);
$user->setFacebookUsername($attr['username']);
$user->addGroup($this->groupRepository->findOneByRole('ROLE_USER'));
$this->entityManager->persist($user);
}
}
break;
}
$this->entityManager->flush();
if (null === $user) {
throw new AccountNotLinkedException(sprintf("User '%s' not found.", $attr['email']));
}
return $user;
}
问题是twitter例如没有给出电子邮件,或者我想在创建新用户之前包含一些额外的字段。有没有办法在创建用户之前将用户重定向到“完整注册”表单?
我试图添加一个请求监听器,在每个请求上,如果用户被记录,检查电子邮件是否存在,如果不存在,则重定向到complete_registration页面,但是如果用户进入主页,注销或其他任何内容,我只想在他试图访问某些用户限制页面时重定向他。
或者更好的是,在他提供所有必需的信息之前不要创建它。
答案 0 :(得分:6)
我自己找到了解决方案,我手动创建了一个新的例外:
<?php
namespace Acme\UserBundle\Exception;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use HWI\Bundle\OAuthBundle\Security\Core\Exception\OAuthAwareExceptionInterface;
/**
* IncompleteUserException is thrown when the user isn't fully registered (e.g.: missing some informations).
*
* @author Alessandro Tagliapietra http://www.alexnetwork.it/
*/
class IncompleteUserException extends AuthenticationException implements OAuthAwareExceptionInterface
{
private $user;
private $accessToken;
private $resourceOwnerName;
/**
* {@inheritdoc}
*/
public function setAccessToken($accessToken)
{
$this->accessToken = $accessToken;
}
/**
* {@inheritdoc}
*/
public function getAccessToken()
{
return $this->accessToken;
}
/**
* {@inheritdoc}
*/
public function getResourceOwnerName()
{
return $this->resourceOwnerName;
}
/**
* {@inheritdoc}
*/
public function setResourceOwnerName($resourceOwnerName)
{
$this->resourceOwnerName = $resourceOwnerName;
}
public function setUser($user)
{
$this->user = $user;
}
public function getUser($user)
{
return $this->user;
}
public function serialize()
{
return serialize(array(
$this->user,
$this->accessToken,
$this->resourceOwnerName,
parent::serialize(),
));
}
public function unserialize($str)
{
list(
$this->user,
$this->accessToken,
$this->resourceOwnerName,
$parentData
) = unserialize($str);
parent::unserialize($parentData);
}
}
这样,在自定义Oauth用户提供程序中,当我检查用户是否存在或创建新用户时,我检查是否缺少必填字段:
if (!$user->getEmail()) {
$e = new IncompleteUserException("Your account doesn't has a mail set");
$e->setUser($user);
throw $e;
}
在这种情况下,用户将被重定向到登录表单,会话中出现该异常,因此在登录页面中我会这样做:
if($error instanceof IncompleteUserException) {
$session->set(SecurityContext::AUTHENTICATION_ERROR, $error);
return $this->redirect($this->generateUrl('register_complete'));
}
它将被重定向到异常中带有$ user的表单,因此它只能询问丢失的信息,然后登录用户。
答案 1 :(得分:1)
我在迁移到sf网站时遇到了类似的问题。迁移后,我希望迁移的用户完成他们的个人资料,而新注册的用户可以立即开始。
我使用RequestListener解决了类似于您的想法的问题,但添加了一个允许用户使用但未完成其个人资料的页面白名单。根据您希望用户在未完成其配置文件的情况下访问的页数,您可能还会考虑使用黑名单。
我没有检查特定字段的存在,如果重定向到配置文件完成页面但添加了一个角色&#34; ROLE_MIGRATION&#34;迁移用户数据库时。在您的情况下,您可以在通过oauth创建用户时添加角色。
这是我的请求监听器的代码:
public function onRequest(GetResponseEvent $evt)
{
if (HttpKernelInterface::MASTER_REQUEST !== $evt->getRequestType())
{
return;
}
$token = $this->securityContext->getToken();
if(!is_object($token)) or not migrating
{
// user is not logged in
return;
}
$user = $token->getUser();
if(!$user instanceof User || !$user->hasRole('ROLE_MIGRATING'))
{
// different user class or already migrated
return;
}
$openPaths = array(
'/start-2.0',
'/css',
'/js',
'/images',
'/media',
'/geo',
'/_wdt',
'/logout', or not migrating
'/terms',
'/contact',
'/about',
'/locale/set'
);
foreach($openPaths as $p)
{
if(strpos($evt->getRequest()->getPathInfo(),$p)===0)
{
// path is open for migrating users
return;
}
}
header('Location: /start-2.0');
exit;
}