我正在开发一个Symfony 2应用程序,用户必须在登录过程中选择一个配置文件.
用户可能有多个配置文件可供使用,他们只知道自己的配置文件.首先,我需要提示输入用户名和密码,如果这些是正确的,我不应该登录用户,我需要提示用户将在会话期间使用的配置文件.
因此,我显示一个带有用户名和密码字段的表单,并使用Ajax请求发送它,如果用户名和密码正确,该请求将使用配置文件列表进行响应,否则将响应错误代码.最后,用户使用用户名,密码和配置文件登录系统.
问题是我不知道如何检查身份验证数据是否正确(使用我的所有身份验证管理器,用户提供程序等)来完成此中间步骤(提示配置文件),而不实际记录用户.
谁能帮我这个?
小智 35
@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
}
小智 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;
我使用@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);
| 归档时间: | 
 | 
| 查看次数: | 14277 次 | 
| 最近记录: |