15

我正在开发一个 Symfony 2 应用程序,用户必须在登录过程中选择一个配置文件。

用户可能有多个要使用的配置文件,他们只知道自己的配置文件。所以首先,我需要提示输入用户名和密码,如果正确,我不应该登录用户,我需要提示用户将在会话期间使用的配置文件。

因此,我展示了一个带有用户名和密码字段的表单,并使用 Ajax 请求发送它,如果用户名和密码正确或错误代码,该请求将使用配置文件列表进行响应。最后,用户使用用户名、密码和配置文件登录系统。

问题是我不知道如何检查身份验证数据是否正确(使用我所有的身份验证管理器、用户提供程序等)来完成这个中间步骤(提示输入配置文件)而实际上没有记录用户。

谁能帮我这个?

4

6 回答 6

37

@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
}
于 2014-02-19T11:10:25.207 回答
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;
于 2012-07-10T03:43:49.153 回答
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);
于 2017-05-10T09:14:41.610 回答
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'));
于 2013-09-03T11:18:45.330 回答
1

在 Symfony 4 中,建议在控制器中使用 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));
}
于 2019-06-28T14:52:26.023 回答
0

Symfony 5.4

密码验证可以使用UserPasswordHasherInterface来完成

use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class AuthenticaitonServices
{    
    public function __construct(UserPasswordHasherInterface $hasher)
    {
        $this->hasher = $hasher;
    }

    public function validate($request)
    {
         $form = [
            "username" => $request->request->get("_username"),
            "password" => $request->request->get("_password")
         ];

         if(!$this->hasher->isPasswordValid($user, $form['password']))
         {
             // Incorrect Password
         } else {
             // Correct Password
         }

isPasswordValid返回一个 bool 响应

如果有人在 Symfony 5.4 中检查密码验证解决方案。上面的代码用于验证从登录表单发布的密码。

希望这会有所帮助。

于 2022-03-01T19:41:14.987 回答