【问题标题】:Manual authentication check Symfony 2手动身份验证检查 Symfony 2
【发布时间】:2012-05-12 10:18:08
【问题描述】:

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

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

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

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

谁能帮我解决这个问题?

【问题讨论】:

    标签: symfony


    【解决方案1】:

    @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
    }
    

    【讨论】:

    • 一个救命的答案。通过一些微小的调整,上述内容也适用于 Symfoy 4.2 。非常感谢。
    【解决方案2】:

    您可以执行类似的操作来检索用户并手动测试密码 -

    $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;
    

    【讨论】:

    • 我强烈建议您查看@Piotr Polak 解决方案,因为它适用于所有密码编码器。
    • 不要编辑答案来完全改变它。相反,请为正确的答案投票。
    【解决方案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);
    

    【讨论】:

    • 这也可以在 Symfony 4 中使用——尽管在 4 中不需要在 service.yaml 中声明服务,它们会自动连接。
    【解决方案4】:

    我可以在控制器上验证我的用户的唯一方法是发出子请求然后重定向。这是我的代码,我使用的是 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'));
    

    【讨论】:

      【解决方案5】:

      在 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));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-04
        • 1970-01-01
        • 2012-09-05
        • 1970-01-01
        • 2014-03-24
        • 2022-07-16
        • 2016-03-16
        • 1970-01-01
        相关资源
        最近更新 更多