Symfony 4,登录,如何调试错误“无效凭据”?

Posted

技术标签:

【中文标题】Symfony 4,登录,如何调试错误“无效凭据”?【英文标题】:Symfony 4, Login, how debug the error 'Invalid credentials'? 【发布时间】:2018-06-11 12:42:43 【问题描述】:

从 symfony 4 开始,我想创建一个简单的身份验证表单。我创建了一个用户类(标识符是电子邮件字段,而不是“用户名”,我创建了一个类控制器并配置了 security.yml 文件。

我用这个静态方法创建了一些用户:(对于测试,默认密码是'test')

class User implements \Serializable, UserInterface

// ...
  public static function new_alea($email, $isActive = false, $password="test")
    $instance = new self();
    $instance->isActive = $isActive;
    $instance->email = $email;

    $brypt = new BCryptPasswordEncoder(4);
    $instance->password = $brypt->encodePassword($password, null);

    return $instance;
  
// ...

它的工作,我的数据库中有一些用户使用加密密码。

但是当我进入表单页面并尝试登录(填写电子邮件/密码字段并单击提交按钮)时,我收到错误“凭据无效”。

这个错误意味着什么?如何/在哪里调试我的代码以查找为什么会发生此错误?

下面,我的代码的主要部分,也许你会看到一个我没有看到的错误:

security.yaml 文件:

security:
    encoders:
        App\Entity\User:
            algorithm: bcrypt
    providers:
        my_db_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        main:
            provider: my_db_provider
            anonymous: ~
            form_login:
                login_path: login
                check_path: login
    role_hierarchy:
        # ...

用户实体类:

class User implements \Serializable, UserInterface

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

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

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

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

    private $plainPassword;

    public static function new_alea($email, $isActive = false, $password="coucou")
        $instance = new self();
        $instance->isActive = $isActive;
        $instance->email = $email;

        $brypt = new BCryptPasswordEncoder(4);
        $instance->password = $brypt->encodePassword($password, null);

        return $instance;
    

    public function eraseCredentials() 
        $this->plainPassword = null;
    

    public function serialize() 
        return serialize(array(
            $this->id,
            $this->email,
            $this->password,
        ));
    

    public function unserialize($serialized) 
        list (
            $this->id,
            $this->email,
            $this->password,
            ) = unserialize($serialized);
    

    public function getRoles() 
        return array('ROLE_ADMIN');
    

    public function getPassword() 
        return $this->password;
    

    public function setPassword($password) 
        $this->password = $password;
    

    public function getUsername() 
        return $this->email;
    

    public function setUsername($email) 
        $this->email = $email;
    

    public function getPlainPassword() 
        return $this->plainPassword;
    

    public function setPlainPassword($plainPassword): void 
        $this->plainPassword = $plainPassword;
    

    // and others getters/setters

登录控制器:

class LoginController extends Controller

    /**
     * @Route("/login", name="login")
     */
    public function login(Request $request, AuthenticationUtils $authUtils)
    
        // get the login error if there is one
        $error = $authUtils->getLastAuthenticationError();

        // last username entered by the user
        $email = $authUtils->getLastUsername();

        return $this->render('frontend/log/login.html.twig', array(
            'email' => $email,
            'error' => $error,
        ));
    

还有模板 login.html.twig 文件:

% extends 'base.html.twig' %

% block body %

    % if error %
        <div> error.messageKey|trans(error.messageData, 'security') </div>
    % endif %

    <form action=" path('login') " method="post">
        <label for="email">Email:</label>
        <input type="text" id="email" name="_email" value=" email " />

        <label for="password">Password:</label>
        <input type="password" id="password" name="_password" />

        #
            If you want to control the URL the user
            is redirected to on success (more details below)
            <input type="hidden" name="_target_path" value="/account" />
        #

        <button type="submit">login</button>
    </form>

% endblock body %

【问题讨论】:

在 User 的 ... 部分中,您是否实现了所有 UserInterface 方法?特别是getUsername()? 是的,你可以在我的粘贴中看到 getUsername() :) 嗯。在安全性下:添加“hide_user_not_found: false”这会将消息更改为“找不到用户”或“无效密码”。这将验证问题出在密码上并缩小范围。 顺便说一下,如果您查看Security Config Docs,您会看到 bcrypt 编码器的默认成本为 13。这也可能是问题所在。 bcrypt encoder details 啊哈!在您的表单中,name="_email" 应该是 name="_username" 或者在 form_login 下被覆盖。 【参考方案1】:

嗨,我今天遇到了同样的问题,对我来说,这是我在字符串密码中限制了字符数。所以密码错误,因为编码占用了太多字符。所以我删除了字符的限制并且它起作用了。

【讨论】:

【参考方案2】:

只需在“frontend”错误消息下方输出 error 即可获取完整的堆栈跟踪等...

【讨论】:

【参考方案3】:

在您的登录模板中,添加 dump(error) 。它包括真正的错误消息(通常就足够了),以及整个堆栈跟踪(如果需要)。而且格式比 error 更好:

% if error %
      dump(error) 
    <div> error.messageKey|trans(error.messageData, 'security') </div>
% endif %

【讨论】:

【参考方案4】:

我遇到了类似的问题,我通过将密码从纯文本更改为编码版本来解决。

# I create users by fixtures
$user->setEmail('admin@admin');
$user->setPassword('admin'); // Wrong

$user->setPassword($this->passwordEncoder->encodePassword(
    $user,
    'admin'
)); // Correct

官方参考:https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html#accessing-services-from-the-fixtures

【讨论】:

【参考方案5】:

使用两个具有相同功能名称和不同标签名称的路由器路径,以便在用户名和密码正确时移动到您的登录路径。当您的密码或用户名无效时,它将移动到另一个路径。

示例:

index:
 path: /
 controller: App\Controller\DefaultController::login

login:
  path: /login
  controller: App\Controller\DefaultController::login

【讨论】:

以上是关于Symfony 4,登录,如何调试错误“无效凭据”?的主要内容,如果未能解决你的问题,请参考以下文章

spring security reactive - 如何调试“无效凭据”错误?

Google OAuth 登录错误:凭据无效

令牌在尝试刷新后被取消身份验证

如何在 Symfony 4 中创建登录页面而不会出现“InvalidConfigurationException”错误?

开发笔记单点登录CAS测试登录Invalid credentials无效凭据

Symfony 5 调试工具栏未显示在错误页面上