有没有人有相关经验或者能够指点我正确的方向?
Symfony 4.0
在Symfony 3到4的过程中,这个过程并没有改变,但是下面的例子使用了新推荐的AbstractController
。在父类的getSubscribedServices
方法中注册了security.token_storage
和session
服务,因此您不需要在控制器中添加这些服务。
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use YourNameSpace\UserBundle\Entity\User;
class LoginController extends AbstractController{
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->container->get('security.token_storage')->setToken($token);
$this->container->get('session')->set('_security_main', serialize($token));
// The user is now logged in, you can redirect or do whatever.
}
}
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中更新它即可。// 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
}
}
为创建令牌,您需要创建一个UsernamePasswordToken
。它接受4个参数:用户实体、用户凭据、防火墙名称和用户角色。您不需要提供用户凭据即可使用该令牌。
如果您打算立即重定向,我并不100%确定将令牌设置在security.context
上是必要的。但这似乎没有什么问题,所以我将其保留了下来。
然后是重要的部分——设置会话变量。变量命名约定是_security_
后跟您的防火墙名称,在本例中是main
,因此为_security_main
。
终于想通了。
在用户注册后,您应该可以访问一个实例对象,该对象是您在提供程序配置中设置为用户实体的对象。解决方案是使用该用户实体创建一个新的令牌,并将其传递给安全上下文。以下是基于我的设置的示例:
RegistrationController.php:
$token = new UsernamePasswordToken($userEntity, null, 'main', array('ROLE_USER'));
$this->get('security.context')->setToken($token);
这里的main
是你的应用程序防火墙的名称(感谢@Joe)。就是这样,系统现在将您的用户视为刚创建的用户并完全登录。
编辑:根据@Miquel的评论,我已更新控制器代码示例以包括新用户的合理默认角色(尽管显然可以根据您的应用程序的特定需求进行调整)。
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
- MrGlass$this->container->get('security.authorization_checker')
代替。 - Ronanpublic function logUser(UserInterface $user) {
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->container->get('security.context')->setToken($token);
}
我正在使用Symfony 2.2,我的经验与Problematic略有不同,因此这是一个结合了这个问题所有信息和我的一些信息的版本。
我认为Joe关于$providerKey
的价值是错误的,它是UsernamePasswordToken
构造函数的第三个参数。 这应该是一个认证(不是用户)提供程序的密钥。 它由身份验证系统用于区分为不同提供程序创建的令牌。 任何从UserAuthenticationProvider
继承的提供程序都将仅验证其提供程序密钥与其自身匹配的令牌。 例如,UsernamePasswordFormAuthenticationListener
将其创建的令牌的密钥设置为与其相应的DaoAuthenticationProvider
匹配。这使单个防火墙可以拥有多个用户名+密码提供程序而不会相互冲突。 因此,我们需要选择一个不会与其他提供程序冲突的密钥。 我使用'new_user'
。EventDispatcher
并手动触发该事件。我决定不触发交互式登录事件,因为我们是隐式地对用户进行身份验证,而不是响应显式的登录请求。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
,因此我可以直接将它们与令牌一起使用。如果您的实体没有实现UserInterface
,则必须找到一种将它们转换为UserInterface
实例的方法。UsernamePasswordToken
。此外,使用正确的提供程序意味着事件将为您处理。// src/Controller/RegistrationController.php
// ...
use App\Security\LoginFormAuthenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
class RegistrationController extends AbstractController
{
public function register(LoginFormAuthenticator $authenticator, GuardAuthenticatorHandler $guardHandler, Request $request)
{
// ...
// after validating the user and saving them to the database
// authenticate the user and use onAuthenticationSuccess on the authenticator
return $guardHandler->authenticateUserAndHandleSuccess(
$user, // the User object you just created
$request,
$authenticator, // authenticator whose onAuthenticationSuccess you want to use
'main' // the name of your firewall in security.yaml
);
}
}
重要提示:确保您的防火墙未设置为“lazy”。如果是,则令牌将永远不会存储在会话中,您将永远无法登录。
firewalls:
main:
anonymous: ~ # this and not 'lazy'
use App\Security\LoginFormAuthenticator;
的内容是什么? - allan.simon“找不到类“Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken”的令牌的任何身份验证提供程序"
。 - Laurent W.调用
$this->container->get('security.context')->setToken($token);
只会影响当前使用的路由的security.context
。
即,您只能从防火墙控制下的 URL 登录用户。
(如果需要,可以为路由添加一个异常 - IS_AUTHENTICATED_ANONYMOUSLY
)
firewalls:
foobar:
pattern: /foo/
blablabla
作为 UsernamePasswordToken 的第三个参数传递,它也会起作用吗?这个参数是什么意思? - Mikhail我尝试了这里的所有答案,但都没有起作用。我唯一能在控制器上验证我的用户的方法是通过进行子请求,然后重定向。以下是我的代码,我正在使用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'));
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.).
}
无需像其他解决方案中那样分派事件。
灵感来自于FOS\UserBundle\Controller\RegistrationController::authenticateUser
(来自composer.json FOSUserBundle版本:"friendsofsymfony/user-bundle": "~1.3")
$this->get('session')->set('_security_main', serialize($token));
,一些疯狂的事情正在发生。谢谢,@Chausser! - Dmytro_security_admin
将获得您提供的用户的UsernamePasswordToken
,即您将从admin
防火墙中“断开连接”。有什么办法可以维护“admin”防火墙的令牌? - gremosetToken(..)
或者尚未通过身份验证时才能正常工作。 - gremo