我正在开发一个Symfony 2应用程序,用户必须在登录过程中选择一个配置文件。
用户可能有多个配置文件可供使用,他们只知道自己的配置文件。首先,我需要提示输入用户名和密码,如果这些是正确的,我不应该登录用户,我需要提示用户在会话期间使用的配置文件。
因此,我显示一个带有用户名和密码字段的表单,并使用Ajax请求发送该表单,如果用户名和密码正确,该请求将使用配置文件列表进行响应,否则返回错误代码。最后,用户使用用户名,密码和配置文件登录系统。
问题在于我不知道如何检查身份验证数据是否正确(使用我的所有身份验证管理器,用户提供程序等)来完成此中间步骤(提示配置文件),而无需事实记录用户。 / p>
任何人都可以帮我吗?
答案 0 :(得分:34)
@ Jordon代码的一个问题是,它不适用于为同一密码生成不同哈希值的散列算法(例如bcrypt故事内部的参数,迭代次数和盐)。使用Encoder的isPasswordValid比较密码更为正确。
以下是改进的代码,可以正常使用bcrypt:
$username = trim($this->getRequest()->query->get('username'));
$password = trim($this->getRequest()->query->get('password'));
$em = $this->get('doctrine')->getManager();
$query = $em->createQuery("SELECT u FROM \Some\Bundle\Entity\User u WHERE u.username = :username");
$query->setParameter('username', $username);
$user = $query->getOneOrNullResult();
if ($user) {
// Get the encoder for the users password
$encoder_service = $this->get('security.encoder_factory');
$encoder = $encoder_service->getEncoder($user);
// Note the difference
if ($encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
// Get profile list
} else {
// Password bad
}
} else {
// Username bad
}
答案 1 :(得分:17)
您可以执行以下操作来检索用户并手动测试密码 -
$username = trim($this->getRequest()->query->get('username'));
$password = trim($this->getRequest()->query->get('password'));
$em = $this->get('doctrine')->getEntityManager();
$query = $em->createQuery("SELECT u FROM \Some\Bundle\Entity\User u WHERE u.username = :username");
$query->setParameter('username', $username);
$user = $query->getOneOrNullResult();
if ($user) {
// Get the encoder for the users password
$encoder_service = $this->get('security.encoder_factory');
$encoder = $encoder_service->getEncoder($user);
$encoded_pass = $encoder->encodePassword($password, $user->getSalt());
if ($user->getPassword() == $encoded_pass) {
// Get profile list
} else {
// Password bad
}
} else {
// Username bad
}
从客户端获取配置文件后,您也可以轻松地在AJAX服务器控制器中手动执行登录 -
// Get the security firewall name, login
$providerKey = $this->container->getParameter('fos_user.firewall_name');
$token = new UsernamePasswordToken($user, $password, $providerKey, $user->getRoles());
$this->get("security.context")->setToken($token);
// Fire the login event
$event = new InteractiveLoginEvent($this->getRequest(), $token);
$this->get("event_dispatcher")->dispatch("security.interactive_login", $event);
可能需要一些使用线 -
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
答案 2 :(得分:3)
我使用@Jordon和@Potor Polak中的代码将逻辑包装在使用当前访问令牌验证密码的独立服务中。也许有些人需要这个:
services.yml
:
app.validator.manual_password:
class: AppBundle\Service\ManualPasswordValidator
arguments:
- '@security.token_storage'
- '@security.encoder_factory'
ManualPasswordValidator.php
:
<?php
namespace AppBundle\Service;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
/**
* Class ManualPasswordValidator
*
* @package AppBundle\Service
*/
class ManualPasswordValidator
{
/**
* @var EncoderFactory
*/
protected $encoderFactory;
/**
* @var TokenStorage
*/
protected $tokenStorage;
/**
* ManualPasswordValidator constructor.
*
* @param EncoderFactory $encoderFactory
* @param TokenStorage $tokenStorage
*/
public function __construct(TokenStorage $tokenStorage, EncoderFactory $encoderFactory)
{
$this->encoderFactory = $encoderFactory;
$this->tokenStorage = $tokenStorage;
}
/**
* @param $password
* @return bool
*/
public function passwordIsValidForCurrentUser($password)
{
$token = $this->tokenStorage->getToken();
if ($token) {
$user = $token->getUser();
if ($user) {
$encoder = $this->encoderFactory->getEncoder($user);
if ($encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
return true;
}
}
}
return false;
}
}
在此之后,您可以在任意位置注入ManualPasswordValidator
,并使用它:
$password = $request->get('password');
$passwordIsValid = $this->manualPasswordValidator->passwordIsValidForCurrentUser($password);
答案 3 :(得分:1)
我可以在控制器上验证用户身份的唯一方法是进行子请求,然后重定向。这是我的代码,我使用的是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'));
答案 4 :(得分:0)
在Symfony 4中,建议在Controllers中使用UserPasswordEncoderInterface。只需将UserPasswordEncoderInterface作为参数添加到要在其中检查密码的函数中,然后添加以下代码。
public function changePasswordAction($old, $new, UserPasswordEncoderInterface $enc) {
// Fetch logged in user object, can also be done differently.
$auth_checker = $this->get('security.authorization_checker');
$token = $this->get('security.token_storage')->getToken();
$user = $token->getUser();
// Check for valid password
$valid = $encoder->isPasswordValid($user, $old);
// Do something, e.g. change the Password
if($valid)
$user->setPassword($encoder->encodePassword($user, $new));
}