php - Symfony 6 登录不运行身份验证

标签 php symfony symfony6

我正在尝试在 symfony 6 中制作一个小应用程序来练习,但无法登录。

我使用了命令make:usermake:crud usermake:auth,并且我让应用程序构建了帮我登录。

问题是,我设法正确注册用户(散列密码),但是当我尝试登录时,它只会将我重定向到同一页面,甚至不会向我显示错误消息。

我注意到,登录应用程序时不会将表单发送到App\Security\UserAuthenticator。在 symfony 的早期版本中,应用程序按照应有的方式直接为我配置了所有这些。

这是我的SecurityController:

class SecurityController extends AbstractController
{
    #[Route(path: '/login', name: 'app_login')]
    public function login(AuthenticationUtils $authenticationUtils): Response
    {
        if ($this->getUser()) {
            return $this->redirectToRoute('app_home');
        }

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

        return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
    }

    #[Route(path: '/logout', name: 'app_logout')]
    public function logout(): void
    {
        throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
    }
}

login.html.twig:

{% extends 'base.html.twig' %}

{% block title %}Log in!{% endblock %}

{% block body %}
<form method="post">
    {% if error %}
        <div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
    {% endif %}

    {% if app.user %}
        <div class="mb-3">
            You are logged in as {{ app.user.userIdentifier }}, <a href="{{ path('app_logout') }}">Logout</a>
        </div>
    {% endif %}

    <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
    <label for="inputUsername">Username</label>
    <input type="text" value="{{ last_username }}" name="username" id="inputUsername" class="form-control" autocomplete="username" required autofocus>
    <label for="inputPassword">Password</label>
    <input type="password" name="password" id="inputPassword" class="form-control" autocomplete="current-password" required>

    <input type="hidden" name="_csrf_token"
           value="{{ csrf_token('authenticate') }}"
    >

    <button class="btn btn-lg btn-primary" type="submit">
        Sign in
    </button>
</form>
{% endblock %}

用户身份验证器:

class UserAuthenticator extends AbstractLoginFormAuthenticator
{
    use TargetPathTrait;

    public const LOGIN_ROUTE = 'app_login';

    private UrlGeneratorInterface $urlGenerator;

    public function __construct(UrlGeneratorInterface $urlGenerator)
    {
        $this->urlGenerator = $urlGenerator;
    }

    public function authenticate(Request $request): Passport
    {
        $username = $request->request->get('username', '');

        $request->getSession()->set(Security::LAST_USERNAME, $username);

        return new Passport(
            new UserBadge($username),
            new PasswordCredentials($request->request->get('password', '')),
            [
                new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')),
            ]
        );
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
            return new RedirectResponse($targetPath);
        }

        // For example:
        return new RedirectResponse($this->urlGenerator->generate('app_home'));
    }

    protected function getLoginUrl(Request $request): string
    {
        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    }
}

security.yaml:

security:
    # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: username
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            provider: app_user_provider
            custom_authenticator: App\Security\UserAuthenticator
            logout:
                path: app_logout
                # where to redirect after logout
                # target: app_any_route

            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#the-firewall

            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        # - { path: ^/admin, roles: ROLE_ADMIN }
        # - { path: ^/profile, roles: ROLE_USER }

when@test:
    security:
        password_hashers:
            # By default, password hashers are resource intensive and take time. This is
            # important to generate secure password hashes. In tests however, secure hashes
            # are not important, waste resources and increase test times. The following
            # reduces the work factor to the lowest possible values.
            Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
                algorithm: auto
                cost: 4 # Lowest possible value for bcrypt
                time_cost: 3 # Lowest possible value for argon
                memory_cost: 10 # Lowest possible value for argon

我希望你能帮我一把,我不明白发生了什么,而且我在谷歌搜索时读到的一些内容对我没有帮助。谢谢。

最佳答案

这里是创建用户和登录的完整过程:

Symfony 6.1

$ php bin/console make:user
$ php bin/console make:migration
$ php bin/console doctrine:migrations:migrate

创建一个临时用户进行测试(加密密码为“test”)

INSERT INTO `user` (`id`, `email`, `roles`, `password`) VALUES (1, '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="244e4b4c4a404b4164574d50410a474b49" rel="noreferrer noopener nofollow">[email protected]</a>', '["ROLE_ADMIN"]', '$2y$13$zMYKGkggUiUdAGedrgpXF.jlArzta9k3UgBCKEvoF1ILsbbSxx8by');

创建登录表单

$ php bin/console make:controller Login

安全配置

# config/packages/security.yaml
security:
# ...

    firewalls:
        main:
            # ...
            form_login:
                # "app_login" is the name of the route created previously
                login_path: app_login
                check_path: app_login
                
            logout:
                path: app_logout

注销路线

# api/config/routes.yaml
# ...
app_logout:
    path: /logout
    methods: GET
# ...

CSFR 保护

# config/packages/security.yaml
security:
    # ...

    firewalls:
        secured_area:
            # ...
            form_login:
                # ...
                enable_csrf: true

# config/packages/framework.yaml
framework:
    # ...
    csrf_protection: ~

登录 Controller

// src/Controller/LoginController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class LoginController extends AbstractController
{
    #[Route('/login', name: 'app_login')]
    public function index(AuthenticationUtils $authenticationUtils): Response
    {
      // get the login error if there is one
      $error = $authenticationUtils->getLastAuthenticationError();
      
      // last username entered by the user
      $lastUsername = $authenticationUtils->getLastUsername();
      
      return $this->render('login/index.html.twig', [
          'controller_name' => 'LoginController',
          'last_username' => $lastUsername,
          'error'         => $error
      ]);
    }
}

登录模板

{# templates/login/index.html.twig #}
{% extends 'base.html.twig' %}

{# ... #}

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

    <form action="{{ path('app_login') }}" method="post">
        <label for="username">Email:</label>
        <input type="text" id="username" name="_username" value="{{ last_username }}"/>

        <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
        <input type="hidden" name="_target_path" value="/api"/> #}
        <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
        
        <button type="submit">login</button>
    </form>
{% endblock %}

关于php - Symfony 6 登录不运行身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72599426/

相关文章:

javascript - 获取更改事件 javascript 上所有选择选项的值

php - 我的 html 表单值没有发送到 MYSQL 数据库

交响乐团 : What is the meaning of auto_mapping and auto_generate_proxy_classes

php - Symfony 6.3 迁移导致无状态验证器强制请求无状态的问题

webpack - Symfony 6 与 TailwindCSS 3 : Tailwind components css not generated

php - 在 MySQL 中存储动态数据和数据类型

symfony - 在应用 DataTransformer 之前验证字段

Symfony - SQLSTATE-23000 : Integrity constraint violation: 1022 Can't write duplicate key

php - 文本搜索 - 突出显示搜索短语