Symfony 3 无法使用 ajax 登录

Posted

技术标签:

【中文标题】Symfony 3 无法使用 ajax 登录【英文标题】:Symfony 3 unable to login with ajax 【发布时间】:2017-12-06 16:41:14 【问题描述】:

首先,我没有在这个项目中使用 FOSUserBundle。所以,让我们把它排除在外。

我可以注册用户,但无法登录。

我验证了表单已发布到 LoginController 并且它生成了 authenticationUtils 对象,但它没有生成错误,即使下面有一个错误:

$error = $authUtils->getLastAuthenticationError();

否则不会产生任何错误。它默默地失败了。即使我提供了正确的凭据,_wdt 仍会继续显示为匿名。

security.yml

security:
encoders:
    UsedBundle\Entity\User:
        algorithm: bcrypt

providers:
    db_provider:
        entity:
            class: UsedBundle:User
            property: email

firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false

    main:
        anonymous: ~
        provider: db_provider
        form_login: 
            username_parameter: _email

登录控制器: UsedBundle\Controller\LoginController

namespace UsedBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\JsonResponse;


class LoginController extends Controller

/**
 * @Route("/login", name="login")
 */
public function loginAction(Request $request)

    if ($request->isMethod('POST')) 
        var_dump($_POST);
        $authUtils = $this->get('security.authentication_utils');

        // get the login error if there is one
        $error = $authUtils->getLastAuthenticationError();
        var_dump($error);
        var_dump($authUtils);
        if(isset($error))
            $message = $error->getMessageData();
            var_dump($message);
        
        // last username entered by the user
        $lastUsername= $authUtils->getLastUsername();

        return new JsonResponse(array(
            'last_username' => $lastUsername,
            'error'         => $error,)
        );          
    else
        return $this->render('common/login.html.twig');         
    



表单模板:

app\Resources\Views\Common\login.html.twig

% if error is defined and error is not null %
 dump(error) 

<div> error.messageKey|trans(error.messageData, 'security') </div>
% else %
<form action="" method="post" name="login_form" id="login_form" >
    <div class="contact" >
        <input type="email" id="email" name="_email" class="form-control" placeholder="e-mail" value=" % if last_username is defined %
             last_username  
        % endif %
        " />
    </div>

    <div class="contact" >
        <input type="password" id="password" name="_password" placeholder="mot de passe" />
    </div>

    <div>
        <button type="submit" class="sub_ok btn btn-sm" name="submit" >Valider</button>
    </div>
</form>  
% endif %

User 实体设置了 getUsername() 方法来返回电子邮件:

namespace UsedBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * @ORM\Table(name="users")
 * @ORM\Entity(repositoryClass="UsedBundle\Repository\UserRepository")
 * @UniqueEntity(fields="email", message="Email already taken")
 * @UniqueEntity(fields="avatar", message="Username already taken")
 */
class User implements UserInterface, \Serializable

/**
 * @ORM\Column(type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @ORM\Column(type="string", length=50, unique=true)
 * @Assert\Regex(
 *      pattern="/^[A-Za-z0-9\s_\-.]5,50$/",
 *      message="Minimum 5 caracteres, max 50."
 *      )
 */
private $avatar;

/**
 * @ORM\Column(type="string", length=50)
 * @Assert\Regex(
 *      pattern="/^[a-zA-Z\s]5,50$/",
 *      message="Minimum 5 lettres, max 50."
 *      )
 */
private $name;

/**
 * @ORM\Column(type="string", length=64)
 */
private $password;

/**
 * @Assert\Length(max=4096)
 * @Assert\Regex(
 *      pattern="/^.8,50$/",
 *      message="Minimum 8 caracteres, max 50."
 *      )
 */
private $plainPassword;

/**
 * @ORM\Column(type="string", length=100, unique=true)
 * @Assert\NotBlank()
 * @Assert\Email()
 */
private $email;

/**
 * @ORM\Column(type="string", length=50)
 * @Assert\Regex(
 *      pattern="/^[0-9]10,20$/",
 *      message="Minimum 5 lettres, max 50."
 *      )
 */
private $phone;

/**
 * @ORM\Column(type="string", length=50)
 */
private $role;

/**
 * @ORM\Column(type="boolean")
 */
private $isActive;  

/**
 * @ORM\Column(type="string", length=64)
 */
private $userKey;   

/**
 * @ORM\Column(type="datetime")
 * @Assert\DateTime()
 */
private $userKeyTime;

/**
 * @ORM\Column(type="datetime")
 * @Assert\DateTime()
 */
private $dateReg;

/**
 * @ORM\Column(type="string", length=10)
 */
private $blogSubs;

/**
 * Many users for one city
 * @ORM\ManyToOne(targetEntity="City",inversedBy="users")
 * @ORM\JoinColumn(name="city_id", referencedColumnName="id")
 */
private $cityId;

/**
 * one visitor may correspond to one user
 * 
 * @ORM\OneToOne(targetEntity="Visitor", mappedBy="userId")
 */
private $visitor;

public function __construct()

    $this->isActive = false;
    $this->role = 'ROLE_USER';
    //$this->blogSubs = 0;


public function getUsername()

    return $this->email;


public function getSalt()

    return null;


public function getPassword()

    return $this->password;


public function getRoles()

    return array('ROLE_USER');


public function eraseCredentials()



/** @see \Serializable::serialize() */
public function serialize()

    return serialize(array(
        $this->id,
        $this->username,
        $this->password,
        // $this->salt,
    ));


/** @see \Serializable::unserialize() */
public function unserialize($serialized)

    list (
        $this->id,
        $this->username,
        $this->password,
        // $this->salt
    ) = unserialize($serialized);


/**
 * Get id
 *
 * @return integer
 */
public function getId()

    return $this->id;


/**
 * Set avatar
 *
 * @param string $avatar
 *
 * @return User
 */
public function setAvatar($avatar)

    $this->avatar = $avatar;

    return $this;


/**
 * Get avatar
 *
 * @return string
 */
public function getAvatar()

    return $this->avatar;


/**
 * Set name
 *
 * @param string $name
 *
 * @return User
 */
public function setName($name)

    $this->name = $name;

    return $this;


/**
 * Get name
 *
 * @return string
 */
public function getName()

    return $this->name;


/**
 * Set password
 *
 * @param string $password
 *
 * @return User
 */
public function setPassword($password)

    $this->password = $password;

    return $this;


/**
 * Set email
 *
 * @param string $email
 *
 * @return User
 */
public function setEmail($email)

    $this->email = $email;

    return $this;


/**
 * Get email
 *
 * @return string
 */
public function getEmail()

    return $this->email;



/**
 * Set phone
 *
 * @param string $phone
 *
 * @return User
 */
public function setPhone($phone)

    $this->phone = $phone;

    return $this;


/**
 * Get phone
 *
 * @return string
 */
public function getPhone()

    return $this->phone;


/**
 * Set isActive
 *
 * @param boolean $isActive
 *
 * @return User
 */
public function setIsActive($isActive)

    $this->isActive = $isActive;

    return $this;


/**
 * Get isActive
 *
 * @return boolean
 */
public function getIsActive()

    return $this->isActive;


/**
 * Set userKey
 *
 * @param string $email
 *
 * @return User
 */
public function setUserKey( $email )

    $cur_time = time();
    $this->userKey = password_hash($email.$cur_time, PASSWORD_BCRYPT )."\n";
    return $this;


/**
 * Get userKey
 *
 * @return string
 */
public function getUserKey()

    return $this->userKey;


/**
 * Set userKeyTime
 *
 *
 * @return User
 */
public function setUserKeyTime( $hours_added = null )

    if ( $hours_added === null ) 
        $hours_added = 20; 
        $literal_time = \DateTime::createFromFormat('Y-m-d H:i:s',date("Y-m-d H:i:s", strtotime('+' . $hours_added . ' hours')));
    else
        $literal_time = \DateTime::createFromFormat('Y-m-d H:i:s',date("Y-m-d H:i:s", time()));
    
    $this->userKeyTime = $literal_time;
    return $this;


/**
 * Get userKeyTime
 *
 * @return \DateTime
 */
public function getUserKeyTime()

    return $this->userKeyTime;


/**
 * Get dateReg
 *
 * @return \DateTime
 */
public function getDateReg()

    return $this->dateReg;


 /**
 * Set dateReg
 *
 * @return \DateTime
 */
public function setDateReg()

    $literal_time = \DateTime::createFromFormat('Y-m-d H:i:s',date("Y-m-d H:i:s"));
    $this->dateReg = $literal_time;
    return $this;


/**
 * Set role
 *
 * @param string $role
 *
 * @return User
 */
public function setRole($role)

    $this->role = $role;

    return $this;


/**
 * Get role
 *
 * @return string
 */
public function getRole()

    return $this->role;


/**
 * Set blogSubs
 *
 * @param string $blogSubs
 *
 * @return User
 */
public function setBlogSubs($blogSubs)

    $this->blogSubs = $blogSubs;

    return $this;


/**
 * Get blogSubs
 *
 * @return string
 */
public function getBlogSubs()

    return $this->blogSubs;


/**
 * Get plainPassword
 *
 * @return string
 */
public function getPlainPassword()

    return $this->plainPassword;




/**
 * Set cityId
 *
 * @param \UsedBundle\Entity\City $cityId
 *
 * @return User
 */
public function setCityId(\UsedBundle\Entity\City $cityId = null)

    $this->cityId = $cityId;

    return $this;


/**
 * Get cityId
 *
 * @return \UsedBundle\Entity\City
 */
public function getCityId()

    return $this->cityId;


/**
 * Set models
 *
 * @param \UsedBundle\Entity\Visitor $models
 *
 * @return User
 */
public function setModels(\UsedBundle\Entity\Visitor $models = null)

    $this->models = $models;

    return $this;


/**
 * Get models
 *
 * @return \UsedBundle\Entity\Visitor
 */
public function getModels()

    return $this->models;


/**
 * Set visitor
 *
 * @param \UsedBundle\Entity\Visitor $visitor
 *
 * @return User
 */
public function setVisitor(\UsedBundle\Entity\Visitor $visitor = null)

    $this->visitor = $visitor;

    return $this;


/**
 * Get visitor
 *
 * @return \UsedBundle\Entity\Visitor
 */
public function getVisitor()

    return $this->visitor;


表单通过ajax提交,如下:

     $(document).ready(function() 
    $('#login_form').submit(function(e) 
            var str = $("#login_form").serialize();
            $.ajax(
                url: "/login",
                type: "POST",
                dataType: "json",
                data: str,
                success: function(data) 
                    alert(data);
                
        e.preventDefault(); //STOP default action
        );
    );
);

我正在从 Firebug 添加下面的输出。我不确定它是如何产生的,但它显示角色属性为空。仍然不确定为什么。所有用户在数据库上都有 ROLE_USER

  object(Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken)#2384 (6) 
["credentials":"Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken":private]=>
string(8) "senha444"
["providerKey":"Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken":private]=>
string(4) "main"
["user":"Symfony\Component\Security\Core\Authentication\Token\AbstractToken":private]=>
string(22) "myemail@gmail.com"
["roles":"Symfony\Component\Security\Core\Authentication\Token\AbstractToken":private]=>
array(0) 

["authenticated":"Symfony\Component\Security\Core\Authentication\Token\AbstractToken":private]=>
bool(false)
["attributes":"Symfony\Component\Security\Core\Authentication\Token\AbstractToken":private]=>
array(0) 

【问题讨论】:

我最近添加了一个类似的问题,问题是我试图不使用 HTTPS 登录,而在 config.yml framework.session.cookie_secure 中是真的。所以应用程序无法创建 cookie。不知道是不是同一个问题,但我无法登录,我没有错误。 感谢@Picoss,我在 config.yml 上根本没有设置该参数。我确实检查了 /web 目录上的 php.ini,它没有关于它的指令,并且 MAMP 的 php 信息 session.cookie_secure 和 session.cookie_httponly 已关闭。 嗯,我认为您发送 POST 的 url 不正确。您不应该在 /login 上提交表单,而是在 /login_check 上提交。或者,如果您想在 /login 上发布登录表单,请添加您的防火墙配置 login_path 和 check_path。查看有关“如何构建传统登录表单”的 Symfony2 文档:symfony.com/doc/current/security/form_login_setup.html @Picoss,我认为在这种情况下没有必要。 Ajax 将路由路由到正确的控制器。设置是这样的,每个页面都有一个登录表单。如果我把它放在上面,它就会无缘无故地开始重定向。 @BernardA 当您检查分析器时,您可以检查对/login_check URL 的请求吗?您可以使用分析器中的“最后 10 个”按钮检查上一个请求。我还建议您使用debug component,它为您提供dump 功能,而不是var_dump 【参考方案1】:

这不会像上面的设置那样工作。 Symfony 不能很好地与 Ajax 配合使用,因此需要自定义登录。

我已经在this question 上添加了整个设置的答案。

【讨论】:

以上是关于Symfony 3 无法使用 ajax 登录的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2:使用两个不同的用户提供程序登录网站时无法模拟用户

无法从 Symfony 2 上的内存登录中注销

使用Symfony框架在生产服务器上登录失败(由于...无法处理身份验证请求)

使用 Symfony 框架在生产服务器上的用户登录失败(身份验证请求无法处理,因为...)

Symfony 3 - 无法将 token_storage 传递给订阅者

从 Symfony 3.4 迁移到 Symfony 4.4 后,自定义投票器无法按预期工作