自动注册后用户authentication

我们正在从Symfony 2开始构build一个商业应用程序,并且遇到了一些与用户注册stream程有关的问题:在用户创build一个帐户之后,他们应该自动使用这些凭据login,而不是立即被迫再次提供他们的证件。

任何人有任何这方面的经验,或能够指出我在正确的方向吗?

Symfony 2.6.x – Symfony 3.0.x

从symfony 2.6开始, security.context被弃用,以支持security.token_storage 。 控制器现在可以简单地是:

 use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use YourNameSpace\UserBundle\Entity\User; class LoginController extends Controller{ public function registerAction() { $user = //Handle getting or creating the user entity likely with a posted form $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); $this->get('security.token_storage')->setToken($token); $this->get('session')->set('_security_main', serialize($token)); } } 

虽然这已被弃用,但您仍然可以使用security.context因为它已被制作为向后兼容。 准备好为Symfony 3更新它

你可以在这里阅读更多有关2.6安全性的更改: https : //github.com/symfony/symfony/blob/2.6/UPGRADE-2.6.md

Symfony 2.3.x

为了在symfony 2.3中实现这个,你不能再在安全上下文中设置这个标记了。 您还需要将令牌保存到会话中。

假设一个带有防火墙的安全文件,如:

 // app/config/security.yml security: firewalls: main: //firewall settings here 

而且一个控制器的行为也类似:

 use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use YourNameSpace\UserBundle\Entity\User; class LoginController extends Controller{ public function registerAction() { $user = //Handle getting or creating the user entity likely with a posted form $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); $this->get('security.context')->setToken($token); $this->get('session')->set('_security_main',serialize($token)); //Now you can redirect where ever you need and the user will be logged in } } 

对于令牌创build,您将需要创build一个UsernamePasswordToken ,它接受4个参数:用户实体,用户凭证,防火墙名称,用户angular色。 您不需要提供令牌的用户凭据以使其有效。

我不是100%确定在security.context上设置标记是必要的,如果你只是马上redirect。 但它似乎没有受伤,所以我离开了它。

然后是重要的部分,设置会话variables。 命名约定的variables是_security_后面跟着你的防火墙名称,在这种情况下main_security_main

最后把这个弄出来了。

用户注册后,您应该有权访问对象instanceof,无论您在提供程序configuration中设置为用户实体。 解决scheme是用该用户实体创build一个新的令牌,并将其传递到安全上下文中。 这是一个基于我的设置的例子:

RegistrationController.php:

 $token = new UsernamePasswordToken($userEntity, null, 'main', array('ROLE_USER')); $this->get('security.context')->setToken($token); 

其中main是您的应用程序的防火墙名称(谢谢,@Joe)。 这确实是所有的一切。 系统现在认为您的用户是以他们刚创build的用户完全login的。

编辑:Per @ Miquel的评论,我已经更新了控制器代码示例,以包括新用户的合理默认angular色(虽然显然这可以根据您的应用程序的特定需求进行调整)。

我正在使用Symfony 2.2,而且我的经验与有问题的有所不同,所以这是这个问题的所有信息加上一些我自己的信息的组合版本。

我认为Joe对$providerKey的值是错误的,这是UsernamePasswordToken构造函数的第三个参数。 它应该是authentication(而不是用户)提供者的关键。 它被authentication系统用来区分为不同提供者创build的令牌。 任何从UserAuthenticationProvider的提供者将只authentication其提供者密钥与自己相匹配的令牌。 例如, UsernamePasswordFormAuthenticationListener设置它创build的令牌的密钥,以匹配其对应的DaoAuthenticationProvider 。 这可以让一个防火墙拥有多个用户名+密码提供程序,而不需要彼此相互访问。 因此,我们需要select一个不会与其他提供者冲突的密钥。 我使用'new_user'

我的应用程序的其他部分有一些依赖于身份validation成功事件的系统 ,而不是通过在上下文中设置令牌来解决这个问题。 我必须从容器中获取EventDispatcher并手动激发事件。 我决定不再发起一个交互式的login事件,因为我们隐式地对用户进行身份validation,而不是响应明确的login请求。

 use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\AuthenticationEvents; use Symfony\Component\Security\Core\Event\AuthenticationEvent; $user = // get a Symfony user instance somehow $token = new UsernamePasswordToken( $user, null, 'new_user', $user->getRoles() ); $this->get( 'security.context' )->setToken( $token ); $this->get( 'event_dispatcher' )->dispatch( AuthenticationEvents::AUTHENTICATION_SUCCESS, new AuthenticationEvent( $token ) ); 

请注意, $this->get( .. )假定片段位于控制器方法中。 如果您在其他地方使用代码,则必须更改这些代码,以适合环境的方式调用ContainerInterface::get( ... ) 。 碰巧我的用户实体实现了UserInterface所以我可以直接使用它们来使用令牌。 如果你没有,你将不得不find一种方法将其转换为UserInterface实例。

这段代码很有用,但是我感觉像是在围绕Symfony的身份validation体系结构进行攻击,而不是使用它。 使用自己的令牌类实现新的身份validation提供程序可能会更正确,而不是劫持UsernamePasswordToken 。 另外,使用适当的提供者意味着事件是为你处理的。

如果你有一个UserInterface对象(大多数情况下应该是这种情况),你可能需要使用它为最后一个参数实现的getRoles函数。 所以如果你创build一个函数logUser,它应该看起来像这样:

 public function logUser(UserInterface $user) { $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); $this->container->get('security.context')->setToken($token); } 

如果任何人有相同的后续问题,让我回到这里:

调用

 $this->container->get('security.context')->setToken($token); 

只影响当前所用路由的security.context

也就是说,你只能从防火墙控制下的一个URLlogin一个用户。

(如果需要,添加一个路由exception – IS_AUTHENTICATED_ANONYMOUSLY

在这里已经提到了这个问题,这个难以捉摸的$ providerKey参数实际上只不过是你的防火墙规则的名字,在下面的例子中就是'foobar'。

 firewalls: foobar: pattern: /foo/ 

我尝试了所有的答案,没有工作。 我唯一可以在控制器上对用户进行身份validation的方法是进行子请求,然后redirect。 这里是我的代码,我使用的是silex,但是你可以很容易地将它调整到symfony2:

 $subRequest = Request::create($app['url_generator']->generate('login_check'), 'POST', array('_username' => $email, '_password' => $password, $request->cookies->all(), array(), $request->server->all()); $response = $app->handle($subRequest, HttpKernelInterface::MASTER_REQUEST, false); return $app->redirect($app['url_generator']->generate('curriculos.editar')); 

在Symfony版本2.8.11(可能适用于较新版本)中, 如果使用FOSUserBundle,只需执行以下操作:

 try { $this->container->get('fos_user.security.login_manager')->loginUser( $this->container->getParameter('fos_user.firewall_name'), $user, null); } catch (AccountStatusException $ex) { // We simply do not authenticate users which do not pass the user // checker (not enabled, expired, etc.). } 

不需要像在其他解决scheme中看到的那样调度事件。

来自FOS \ UserBundle \ Controller \ RegistrationController :: authenticateUser

(来自composer.json FOSUserBundle版本:“friendsofsymfony / user-bundle”:“〜1.3”)