Login 具有安全和数据库用户的Symfony 4登录表单

Login 具有安全和数据库用户的Symfony 4登录表单,login,symfony4,Login,Symfony4,大约一周前,我在Symfony上是个彻头彻尾的傻瓜,我想我应该在Symfony 4上潜水。在尝试解决基本登录问题一周后,我相信文档仍然缺少一些部分 现在,我找到了一个解决方案,我将与大家分享它,以及一些关于你可能做错了什么的提示。答案的第一部分是建议列表,而第二部分是使用从头开始的工作登录创建项目(假设您已经安装了composer并使用apache之类的服务器)。第1部分:建议 403禁止 检查访问控制:输入security.yaml。规则的顺序会产生影响,因为每次匹配的规则不会超过一个。把最具

大约一周前,我在Symfony上是个彻头彻尾的傻瓜,我想我应该在Symfony 4上潜水。在尝试解决基本登录问题一周后,我相信文档仍然缺少一些部分

现在,我找到了一个解决方案,我将与大家分享它,以及一些关于你可能做错了什么的提示。答案的第一部分是建议列表,而第二部分是使用从头开始的工作登录创建项目(假设您已经安装了composer并使用apache之类的服务器)。

第1部分:建议 403禁止

检查
访问控制:
输入security.yaml。规则的顺序会产生影响,因为每次匹配的规则不会超过一个。把最具体的规则放在首位

登录检查

确保表单操作将您发送到
login\u check
路径,或您在security.yaml中将其更改为的任何路径

还要检查您是否已在控制器或routes.yaml中为
登录检查
路径声明了路由

输入名称

Symfony表单倾向于将输入名称封装在一个数组中,而它只希望它们被命名为
\u username
\u password
(您可以在security.yaml中更改它们)以将其计为登录尝试。因此,检查输入以确保名称属性正确

第2部分:完整Symfony 4登录 项目设置 让我们从创建项目开始。打开cmd/terminal并转到要包含项目文件夹的文件夹

cd .../MyProjects
composer create-project symfony/website-skeleton my-project
cd my-project
现在您已经在…/MyProjects/myproject中创建了一个symfony4网站模板,cmd/terminal位于该路径中,将正确执行其余命令

签入…/MyProjects/myproject/public文件夹以获取.htaccess文件。如果它存在,您就可以了,否则运行以下命令

composer require symfony/apache-pack
您现在可以通过访问my-project.dev/public找到您的站点。如果要删除此公共路径,应使用.htaccess文件,而不是移动index.php

项目设置 1) 编辑.env文件中的
DATABASE\u URL
键,使其与数据库设置相对应

2) 编辑config/packages/security.yaml文件,使其如下所示:

security:
    encoders:
        App\Entity\User:
            algorithm: bcrypt
    providers:
        user:
            entity:
                class: App\Entity\User
                property: username
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            provider: user
            form_login:
                #login_path: login
                #check_path: login_check
                default_target_path: homepage
                #username_parameter: _username
                #password_parameter: _password
            logout:
                #path:   /logout
                #target: /
    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/,      roles: ROLE_USER }
        - { path: ^/admin, roles: ROLE_ADMIN }
<?php

namespace App\Controller;

use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use App\Form\LoginType;

class LoginController extends Controller
{
    /**
     * @Route("/login", name="login")
     */
    public function index(AuthenticationUtils $authenticationUtils)
    {
        $error = $authenticationUtils->getLastAuthenticationError();
        $lastUsername = $authenticationUtils->getLastUsername();
        $form = $this->createForm(LoginType::class);
        return $this->render('login/index.html.twig', [
            'last_username' => $lastUsername,
            'error'         => $error,
            'form'          => $form->createView(),
        ]);
    }

    /**
     * @Route("/logout", name="logout")
     */
    public function logout() {}

    /**
     * @Route("/login_check", name="login_check")
     */
    public function login_check() {}
}
一些解释:

App\Entity\User
是您将在一段时间内创建的用于处理登录的用户实体

用户
提供程序只是一个名称,需要在提供程序和防火墙中进行匹配

如果要允许用户执行以下操作,则必须声明
注销
键。。。嗯,注销

#comment
中的值显示了我们稍后将使用的默认值,并作为您更可能更改的内容的参考

用户实体 用户必须具有角色,但可以具有更多角色。因此,让我们首先为多人关系构建一个
UserRole
实体

php bin/console make:entity userRole
所有实体都以id属性开头。也添加一个
角色

php bin/console make:entity user
用户需要
用户名
密码
角色
属性,但您可以添加更多

让我们编辑src/Entity/User.php文件:

UserInterface
界面添加到
User
类中

use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface
编辑生成的
getRoles()
,使其返回字符串数组

public function getRoles(): array
{
    $roles = $this->roles->toArray();
    foreach($roles as $k => $v) {
        $roles[$k] = $v->getRole();
    }
    return $roles;
}
getSalt()
eraseCredentials()
是实现
UserInterface
接口的函数

public function getSalt()
{
    return null;
}
public function eraseCredentials()
{
}
使用
bcrypt
算法(正如我们在security.yaml中设置的那样),我们不需要盐。它会自动生成一个。不,您不会将此盐存储在任何位置,而且是的,它每次都会为同一密码生成不同的哈希值。但是是的,它会以某种方式起作用(魔法…)

如果需要使用salt的不同算法,则需要在
User
实体上添加
salt
属性

主页 出于测试目的,我们将创建一个主页

php bin/console make:controller homepage
编辑生成的src/Controller/HomepageController.php文件,将根目录更改为/

登录控制器 编辑生成的src/Controller/LoginController.php文件,使其如下所示:

security:
    encoders:
        App\Entity\User:
            algorithm: bcrypt
    providers:
        user:
            entity:
                class: App\Entity\User
                property: username
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            provider: user
            form_login:
                #login_path: login
                #check_path: login_check
                default_target_path: homepage
                #username_parameter: _username
                #password_parameter: _password
            logout:
                #path:   /logout
                #target: /
    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/,      roles: ROLE_USER }
        - { path: ^/admin, roles: ROLE_ADMIN }
<?php

namespace App\Controller;

use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use App\Form\LoginType;

class LoginController extends Controller
{
    /**
     * @Route("/login", name="login")
     */
    public function index(AuthenticationUtils $authenticationUtils)
    {
        $error = $authenticationUtils->getLastAuthenticationError();
        $lastUsername = $authenticationUtils->getLastUsername();
        $form = $this->createForm(LoginType::class);
        return $this->render('login/index.html.twig', [
            'last_username' => $lastUsername,
            'error'         => $error,
            'form'          => $form->createView(),
        ]);
    }

    /**
     * @Route("/logout", name="logout")
     */
    public function logout() {}

    /**
     * @Route("/login_check", name="login_check")
     */
    public function login_check() {}
}
您不必将其与
用户
实体关联

编辑生成的src/Form/LoginType.php文件以添加以下内容:

use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
替换此项:

$builder
    ->add('_username')
    ->add('_password', PasswordType::class)
    ->add('login', SubmitType::class, ['label' => 'Login'])
;
并添加此功能,以防止Symfony通过将您请求的输入名称包含在
login[…]

public function getBlockPrefix() {}
登录模板 编辑templates/login/index.html.twig文件,将此代码添加到
{%block body%}。。。{%endblock%}

{% if error %}
    <div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
{{ form_start(form, {'action': path('login_check'), 'method': 'POST'}) }}
    {{ form_widget(form) }}
{{ form_end(form) }}
这应该已经根据您的
用户
用户角色
实体生成了您的数据库

生成密码 以下命令将为您提供一个哈希密码,您可以直接将其插入数据库。密码将使用security.yaml中指定的算法进行散列


希望这有帮助

非常感谢,文档中缺少一些重要的东西,但效果非常好。对于其他人,请检查访问控制条目的顺序,因为一个放错位置的条目可能会阻塞整个过程

    access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin, roles: ROLE_ADMIN }
这是可行的,但这不是

    access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin, roles: ROLE_ADMIN }
    - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
php bin/console security:encode-password my-password
    access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin, roles: ROLE_ADMIN }
    access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin, roles: ROLE_ADMIN }
    - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }