Форма входа Symfony 4: аутентификация прошла успешно, но аутентификация сразу же теряется после перенаправления - PullRequest
5 голосов
/ 05 июля 2019

Я создал форму входа в систему, следуя этой форме настройки входа в систему doc .

Это нормально работает на localhost , но не на рабочем сервере .

И на localhost, и на prod аутентификация начинается успешно

  1. Аутентификация Guard успешна
  2. Ответ успешного набора аутентификатора Guard
  3. Сохраняет маркер безопасности в сеансе
  4. Совпадающий маршрут "easyadmin

    ### var/log/prod.log output with info level
    [2019-07-05 10:28:46] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\\Controller\\SecurityController::login"},"request_uri":"https://example.com/login","method":"POST"} []
    [2019-07-05 10:28:46] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"main","authenticators":1} []
    [2019-07-05 10:28:46] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"main","authenticator":"App\\Security\\LoginFormAuthenticator"} []
    [2019-07-05 10:28:46] security.DEBUG: Calling getCredentials() on guard authenticator. {"firewall_key":"main","authenticator":"App\\Security\\LoginFormAuthenticator"} []
    [2019-07-05 10:28:46] security.DEBUG: Passing guard token information to the GuardAuthenticationProvider {"firewall_key":"main","authenticator":"App\\Security\\LoginFormAuthenticator"} []
    [2019-07-05 10:28:46] php.INFO: User Deprecated: The "Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder" class is deprecated since Symfony 4.3, use "Symfony\Component\Security\Core\Encoder\NativePasswordEncoder" instead. {"exception":"[object] (ErrorException(code: 0): User Deprecated: The \"Symfony\\Component\\Security\\Core\\Encoder\\BCryptPasswordEncoder\" class is deprecated since Symfony 4.3, use \"Symfony\\Component\\Security\\Core\\Encoder\\NativePasswordEncoder\" instead. at /var/www/clients/client0/web4/web/vendor/symfony/security-core/Encoder/BCryptPasswordEncoder.php:14)"} []
    
    [2019-07-05 10:28:46] security.INFO: Guard authentication successful! {"token":"[object] (Symfony\\Component\\Security\\Guard\\Token\\PostAuthenticationGuardToken: PostAuthenticationGuardToken(user=\"myemail@gmail.com\", authenticated=true, roles=\"ROLE_EDITOR, ROLE_USER\"))","authenticator":"App\\Security\\LoginFormAuthenticator"} []
    
    [2019-07-05 10:28:46] security.DEBUG: Guard authenticator set success response. {"response":"[object] (Symfony\\Component\\HttpFoundation\\RedirectResponse: HTTP/1.0 302 Found\r\nCache-Control: no-cache, private\r\nDate:          Fri, 05 Jul 2019 10:28:46 GMT\r\nLocation:      /backoffice\r\n\r\n<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"UTF-8\" />\n        <meta http-equiv=\"refresh\" content=\"0;url=/backoffice\" />\n\n        <title>Redirecting to /backoffice</title>\n    </head>\n    <body>\n        Redirecting to <a href=\"/backoffice\">/backoffice</a>.\n    </body>\n</html>)","authenticator":"App\\Security\\LoginFormAuthenticator"} []
    
    [2019-07-05 10:28:46] security.DEBUG: Remember me skipped: it is not configured for the firewall. {"authenticator":"App\\Security\\LoginFormAuthenticator"} []
    [2019-07-05 10:28:46] security.DEBUG: The "App\Security\LoginFormAuthenticator" authenticator set the response. Any later authenticator will not be called {"authenticator":"App\\Security\\LoginFormAuthenticator"} []
    [2019-07-05 10:28:46] security.DEBUG: Stored the security token in the session. {"key":"_security_main"} []
    
    [2019-07-05 10:28:46] request.INFO: Matched route "easyadmin". {"route":"easyadmin","route_parameters":{"_controller":"Symfony\\Bundle\\FrameworkBundle\\Controller\\RedirectController::urlRedirectAction","path":"/backoffice/","permanent":true,"scheme":null,"httpPort":80,"httpsPort":443,"_route":"easyadmin"},"request_uri":"https://example.com/backoffice","method":"GET"} []
    

Но, находясь на локальном хосте, я правильно перенаправлен в бэк-офис:

  • Прочитать существующую систему безопасноститокен из сеанса
  • Пользователь был перезагружен от провайдера пользователя

    ### var/log/prod.log (following lines, localhost) 
    [2019-07-05 10:19:29] security.DEBUG: Read existing security token from the session. {"key":"_security_main","token_class":"Symfony\\Component\\Security\\Guard\\Token\\PostAuthenticationGuardToken"} []
    [2019-07-05 10:19:29] security.DEBUG: User was reloaded from a user provider. {"provider":"Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider","username":"raoux.thierry@free.fr"} []
    [2019-07-05 10:19:29] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"main","authenticators":1} []
    [2019-07-05 10:19:29] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"main","authenticator":"App\\Security\\LoginFormAuthenticator"} []
    [2019-07-05 10:19:29] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"main","authenticator":"App\\Security\\LoginFormAuthenticator"} []
    [2019-07-05 10:19:29] cache.INFO: Lock acquired, now computing item "easyadmin.processed_config" {"key":"easyadmin.processed_config"} []
    

В среде Prod вместо:

  • он пропускает шаг: чтение существующего токена безопасности
  • не не обновляет пользователя должным образом
  • , вместо этого он заполняет TokenStorage анонимным токеном
  • Отказано в доступе и возврат к логину URL

    ### var/log/prod.log (same following lines, but from production server) 
    [2019-07-05 10:28:46] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"main","authenticators":1} []
    [2019-07-05 10:28:46] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"main","authenticator":"App\\Security\\LoginFormAuthenticator"} []
    [2019-07-05 10:28:46] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"main","authenticator":"App\\Security\\LoginFormAuthenticator"} []
    [2019-07-05 10:28:46] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
    [2019-07-05 10:28:46] security.DEBUG: Access denied, the user is not fully authenticated; redirecting to authentication entry point. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException(code: 403): Access Denied. at /var/www/clients/client0/web4/web/vendor/symfony/security-http/Firewall/AccessListener.php:72)"} []
    [2019-07-05 10:28:46] security.DEBUG: Calling Authentication entry point. [] []
    [2019-07-05 10:28:46] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\\Controller\\SecurityController::login"},"request_uri":"https://example.com/login","method":"GET"} []
    

security.yaml

security:
    encoders:
        App\Entity\User:
            algorithm: bcrypt
    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            logout:
                path: app_logout
    access_control:
        - { path: ^/backoffice, roles: ROLE_EDITOR} # requires_channel: https

rout.yaml

admin:
  path: /backoffice
  controller: EasyCorp\Bundle\EasyAdminBundle\Controller\EasyAdminController

LoginFormAuthenticator

// use...

class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
    use TargetPathTrait;

    private $entityManager;
    private $urlGenerator;
    private $csrfTokenManager;
    private $passwordEncoder;

    public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
    {
        $this->entityManager = $entityManager;
        $this->urlGenerator = $urlGenerator;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->passwordEncoder = $passwordEncoder;
    }

    public function supports(Request $request)
    {
        return 'app_login' === $request->attributes->get('_route')
            && $request->isMethod('POST');
    }

    public function getCredentials(Request $request)
    {
        $credentials = [
            'email' => $request->request->get('email'),
            'password' => $request->request->get('password'),
            'csrf_token' => $request->request->get('_csrf_token'),
        ];
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $credentials['email']
        );

        return $credentials;
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $token = new CsrfToken('authenticate', $credentials['csrf_token']);
        if (!$this->csrfTokenManager->isTokenValid($token)) {
            throw new InvalidCsrfTokenException();
        }

        $user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);

        if (!$user) {
            // fail authentication with a custom error
            throw new CustomUserMessageAuthenticationException('Email could not be found.');
        }

        return $user;
    }

    public function checkCredentials($credentials, UserInterface $user)
    {
        return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }
        return new RedirectResponse($this->urlGenerator->generate('admin'));
    }

    protected function getLoginUrl()
    {
        return $this->urlGenerator->generate('app_login');
    }
}

Контроллер безопасности

// use...

class SecurityController extends AbstractController
{
    /**
     * @Route("/login", name="app_login")
     */
    public function login(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(
          'security/login.html.twig',
          [
            'last_username' => $lastUsername,
            'error' => $error,
          ]
        );
    }

    /**
     * @Route("/logout", name="app_logout")
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function logout()
    {
        return $this->redirectToRoute('home');
    }
}
//... skipped forgottenPassword and resetPassword methods

РЕДАКТИРОВАТЬ:

php bin/console debug:config security вывод

Current configuration for extension with alias "security"
=========================================================

security:
encoders:
    App\Entity\User:
        algorithm: bcrypt
        hash_algorithm: sha512
        key_length: 40
        ignore_case: false
        encode_as_base64: true
        iterations: 5000
        cost: null
        memory_cost: null
        time_cost: null
        threads: null
providers:
    app_user_provider:
        entity:
            class: App\Entity\User
            property: email
            manager_name: null
firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
        methods: {  }
        user_checker: security.user_checker
        stateless: false
        logout_on_user_change: true
    main:
        anonymous:
            secret: null
        guard:
            authenticators:
                - App\Security\LoginFormAuthenticator
            entry_point: null
        logout:
            path: app_logout
            csrf_parameter: _csrf_token
            csrf_token_id: logout
            target: /
            invalidate_session: true
            delete_cookies: {  }
            handlers: {  }
        methods: {  }
        security: true
        user_checker: security.user_checker
        stateless: false
        logout_on_user_change: true
access_control:
    -
        path: ^/backoffice
        roles:
            - ROLE_EDITOR
        requires_channel: null
        host: null
        port: null
        ips: {  }
        methods: {  }
        allow_if: null
access_decision_manager:
    strategy: affirmative
    allow_if_all_abstain: false
    allow_if_equal_granted_denied: true
access_denied_url: null
session_fixation_strategy: migrate
hide_user_not_found: true
always_authenticate_before_granting: false
erase_credentials: true
role_hierarchy: {  }

РЕДАКТИРОВАТЬ 2

Как прокомментировал @Arno, я отредактировал framework.yaml для сохранения сеансов в каталоге var/ иЯ могу проверить, что этот шаг работает без проблем с разрешениями, каждый раз, когда я нажимаю на форму входа, записывается файл sess_.

Стоит сказать, что если я прокомментирую:

access_control:
    - { path: ^/odelices_admin, roles: ROLE_USER}

, я могу получить доступ к backoffice.

EDIT 3: поведение сессии

Так что теперь сессии сохраняются ввар / сессии / прод.

  1. Я очищаю каталог: sudo rm -r var/sessions/prod/sess_*
  2. Я открываю Chrome и URL, он устанавливает файл cookie PHPSSID с тем же значением, что и в первом файле sess_xyz:

    _sf2_attributes|a:2:{s:19:"_csrf/https-contact";s:43:"Oq-QpN21bI_BUDcVbv0ocyrYsTzQo3aJr80QAk2AR7w";s:19:"_csrf/https-booking";s:43:"z_L4TG7Wg0jydwl5VabfJMx0NBhQgeasuAiqxksLvD8";}_sf2_meta|a:3:{s:1:"u";i:1562668584;s:1:"c";i:1562668584;s:1:"l";s:1:"0";}
    
  3. Я захожу на страницу входа.Новое значение PHPSSID, связанное с новым файлом sess_xyz:

    _sf2_attributes|a:1:{s:24:"_csrf/https-authenticate";s:43:"erWMU-irtptcZodr8UOjFtxiuyE23LbAeFHRnXgcNdc";}_sf2_meta|a:3:{s:1:"u";i:1562668662;s:1:"c";i:1562668662;s:1:"l";s:1:"0";}
    
  4. Я вхожу с правильными значениями.Это создает 3 новых файла ssid_xyz.

    # 1st one shows user logged in with correct roles and so on
    _sf2_attributes|a:3:{s:24:"_csrf/https-authenticate";s:43:"erWMU-irtptcZodr8UOjFtxiuyE23LbAeFHRnXgcNdc";s:23:"_security.last_username";s:21:"user_email@gmail.com";s:14:"_security_main";s:799:"C:67:"Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken":718:{a:2:{i:0;s:4:"main";i:1;a:5:{i:0;O:15:"App\Entity\User":6:{s:19:"^@App\Entity\User^@id";i:1;s:22:"^@App\Entity\User^@email";s:21:"user_email@gmail.com";s:22:"^@App\Entity\User^@roles";a:1:{i:0;s:11:"ROLE_EDITOR";}s:25:"^@App\Entity\User^@password";s:60:"$2y$13$cXaR7Ss.kTH1U.T/Rzi6m.ALsKwWCLDcO5/OIeRDAq02iylmf4us6";s:21:"^@App\Entity\User^@name";s:7:"Thierry";s:13:"^@*^@resetToken";N;}i:1;b:1;i:2;a:2:{i:0;O:41:"Symfony\Component\Security\Core\Role\Role":1:{s:47:"^@Symfony\Component\Security\Core\Role\Role^@role";s:11:"ROLE_EDITOR";}i:1;O:41:"Symfony\Component\Security\Core\Role\Role":1:{s:47:"^@Symfony\Component\Security\Core\Role\Role^@role";s:9:"ROLE_USER";}}i:3;a:0:{}i:4;a:2:{i:0;s:11:"ROLE_EDITOR";i:1;s:9:"ROLE_USER";}}}}";}_sf2_meta|a:3:{s:1:"u";i:1562668713;s:1:"c";i:1562668713;s:1:"l";s:1:"0";}
    
    # 2nd one ...is empty
    
    # 3rd one refers to backoffice url
    _sf2_attributes|a:1:{s:26:"_security.main.target_path";s:42:"https://mywebsite.com/backoffice";}_sf2_meta|a:3:{s:1:"u";i:1562668713;s:1:"c";i:1562668713;s:1:"l";s:1:"0";}
    
    # last one is similar to point 3, before logging, only ssid value differs, and a corresponding cookie is set on Chrome
    _sf2_attributes|a:1:{s:24:"_csrf/https-authenticate";s:43:"3UC5dCRrahc2qhdZ167Jg4HKTJCexf8PFlefibTVpYk";}_sf2_meta|a:3:{s:1:"u";i:1562668713;s:1:"c";i:1562668713;s:1:"l";s:1:"0";}
    

РЕДАКТИРОВАТЬ 4: Пользовательский объект

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
// use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;

/**
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 */
class User implements UserInterface # , EquatableInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

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

    /**
     * @ORM\Column(type="json")
     */
    private $roles = [];

    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     */
    private $password;

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

    /**
     * @var string le token qui servira lors de l'oubli de mot de passe
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    protected $resetToken;

  /*public function __construct($username, $password, array $roles)
  {
    $this->username = $username;
    $this->password = $password;
    $this->roles = $roles;
  }*/


    public function getId(): ?int
    {
        return $this->id;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUsername(): string
    {
        return (string) $this->email;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getPassword(): string
    {
        return (string) $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getSalt()
    {
        // not needed when using the "bcrypt" algorithm in security.yaml
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @return string
     */
    public function getResetToken(): string
    {
      return $this->resetToken;
    }

    /**
     * @param string $resetToken
     */
    public function setResetToken(?string $resetToken): void
    {
      $this->resetToken = $resetToken;
    }

    public function __toString() {
      return $this->getName() ;
    }

/*    public function isEqualTo(UserInterface $user)
    {

      if ($this->password !== $user->getPassword()) {
        return false;
      }


      if ($this->email !== $user->getUsername()) {
        return false;
      }

      return true;
    }*/
}

Стек

Debian Stretch, Nginx+ Varnish : Nginx обрабатывает 443 запроса, передает их в Varnish в качестве прокси-сервера кэша, который доставляет кэшированные объекты или передает запросы в бэкэнд nginx через порт 8083.Это работает как прелесть для другого приложения с похожей логикой входа в систему (единственное отличие - ошибка, которую перенаправляет на easyadmin вместо обычного администратора), поэтому я не думаю, что это связано со стеком.

vhost

server { # this block only redirects www to non www
        listen aaa.bbb.ccc.ddd:443 ssl;
        server_name www.somewebsite.com;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_certificate /var/www/clients/client0/web4/ssl/somewebsite.com-le.crt;
        ssl_certificate_key /var/www/clients/client0/web4/ssl/somewebsite.com-le.key;

        return 301 https://somewebsite.com$request_uri;
}

server { # this block redirects ssl requests to Varnish
        listen aaa.bbb.ccc.ddd:443 ssl;
        server_name somewebsite.com;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_certificate /var/www/clients/client0/web4/ssl/somewebsite.com-le.crt;
        ssl_certificate_key /var/www/clients/client0/web4/ssl/somewebsite.com-le.key;

        location / {
            # Pass the request on to Varnish.
            proxy_pass  http://127.0.0.1;

            # Pass some headers to the downstream server, so it can identify the host.
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            # Tell any web apps that the session is HTTPS.
            proxy_set_header X-Forwarded-Proto https;
            proxy_redirect     off;
        }
}

server { # now sent to backend 
        listen aaa.bbb.ccc.ddd:8083;
        server_name somewebsite.com;
        root   /var/www/somewebsite.com/web/public;

        location / {
            try_files $uri /index.php$is_args$args;
       }
       location ~ ^/index\.php(/|$) {
            fastcgi_pass 127.0.0.1:8998;

            fastcgi_split_path_info ^(.+\.php)(/.*)$;
            include fastcgi_params;

            fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
            fastcgi_param DOCUMENT_ROOT $realpath_root;

            internal;
        }
        location ~ \.php$ {
            return 404;
        }

        error_log /var/log/ispconfig/httpd/somewebsite.com/error.log;
        access_log /var/log/ispconfig/httpd/somewebsite.com/access.log combined;

        location ~ /\. {
                        deny all;
        }
        location ^~ /.well-known/acme-challenge/ {
                        access_log off;
                        log_not_found off;
                        root /usr/local/ispconfig/interface/acme/;
                        autoindex off;
                        try_files $uri $uri/ =404;
        }
        location = /favicon.ico {
            log_not_found off;
            access_log off;
            expires max;
        }
        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }
}

Может ли это быть связано с разрешениями для некоторых каталогов?HTTPS?EasyAdmin?Как я могу убедиться, что маркер безопасности был сохранен в сеансе, даже если он зарегистрирован как сохраненный?Я также попытался изменить access_control на роль ROLE_USER, чтобы любой аутентифицированный пользователь мог получить к нему доступ.Ни за что.

Любая помощь очень ценится.

Ответы [ 3 ]

2 голосов
/ 10 июля 2019

Кончается, что установка Varnish была ошибочной.

Я полностью забыл, что мне нужно указать любой шаблон backoffice, такой как /admin/ , /backoffice/ и другие , которые не будут кэшироватьсяпрокси , но вместо него напрямую передается бэкэнду .

sub vcl_recv {
    # ...
    if (req.url ~ "^/status\.php$" ||
        req.url ~ "^/update\.php$" ||
        req.url ~ "^/install\.php" ||
        req.url ~ "^/admin$" ||
        req.url ~ "^/admin/.*$" ||
        req.url ~ "^/flag/.*$" ||
        req.url ~ "^.*/ajax/.*$" ||
        req.url ~ "^.*/ahah/.*$" ||
        req.url ~ "^/info/.*$" ||
        req.url ~ "^/system/files/.*$" ||
        req.url ~ "^/user" ||
        req.url ~ "^/users/.*$" ||
        req.url ~ "^/user/.*$" ) {

       return (pass);
    }
    # ...

Это уже было настроено для другого приложения Symfony, о котором я упоминал в этом вопросе, и нескольких веб-сайтов Drupal.По крайней мере, это заставило меня глубоко погрузиться в Symfony 4 Процесс аутентификации пользователя , и как его отладить!Может быть, этот шаг за шагом пост отладки поможет дальнейшим читателям ?!

2 голосов
/ 13 июля 2019

Итак, вот мои комментарии в более структурированном виде, чтобы они могли помочь кому-то другому, имеющему проблемы с аутентификацией в Symfony.

Убедитесь, что сеансы сохранены

По умолчанию каждый сеанссохраняется как файл с именем sess_<id> в <project_dir>/var/cache/<env>/sessions или как определено save_path в вашем php.ini, если framework.session.handler имеет значение NULL.Настройте каталог сеанса явным образом и убедитесь, что файл сеанса создается при входе в систему. Если нет, проверьте разрешения для этой папки.

# app/config/config.yml (Symfony 3)
# config/packages/framework.yaml (Symfony 4)
framework:
    session:
        handler_id: 'session.handler.native_file'
        save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'

Cf.https://symfony.com/doc/current/session.html#configuration

Убедитесь, что сеансы указаны правильно и используются

При входе в систему следует создать сеанс с новым идентификатором.Проверьте содержимое файла.Он должен содержать вашего сериализованного пользователя под именем брандмауэра (например, основной), включая ваш идентификатор (например, электронную почту) и ваши роли (например, ROLE_USER).Проблема может быть вызвана неправильной аутентификацией, настройкой безопасности или сериализацией.

_sf2_attributes|a:3:{s:18:"_csrf/authenticate";s:43:"n2oap401u4P4O7m_IhPODZ6Bz7EHl-DDsHxBEl-fhxc";s:23:"_security.last_username";s:10:"foo@bar.de";s:14:"_security_main";s:545:"C:67:"Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken":464:{a:2:{i:0;s:4:"main";i:1;a:5:{i:0;O:15:"App\Entity\User":4:{s:19:"App\Entity\Userid";i:1;s:22:"App\Entity\Useremail";s:10:"foo@bar.de";s:22:"App\Entity\Userroles";a:0:{}s:25:"App\Entity\Userpassword";s:60:"$2y$13$qwbtasafa58lPonX6B5a9eV4lziF7EZWP8NFLAe3blpCJVhQgPVOS";}i:1;b:1;i:2;a:1:{i:0;O:41:"Symfony\Component\Security\Core\Role\Role":1:{s:47:"Symfony\Component\Security\Core\Role\Rolerole";s:9:"ROLE_USER";}}i:3;a:0:{}i:4;a:1:{i:0;s:9:"ROLE_USER";}}}}";}_sf2_meta|a:3:{s:1:"u";i:1563015142;s:1:"c";i:1563015142;s:1:"l";s:1:"0";}

Убедитесь, что при входе в систему в вашем браузере установлен файл cookie с таким же идентификатором.Имя файла cookie определяется session.name в вашем php.ini, по умолчанию это PHPSESSID.Он должен быть отправлен с каждым вашим запросом (например, Cookie: PHPSESSID=lpcf79ff8jdv2iigsgvepnr9bb).Если правильный сеанс существует, но в вашем браузере есть другой файл cookie, возможно, вы сразу же вышли из системы после успешного перенаправления.

Убедитесь, что пользователь обновлен правильно

Идентификатор сеансадолжен меняться только при изменении вашего пользователя (например, при входе и выходе из системы).Если он меняется после обычных запросов (например, вы сразу же вышли из системы) или ваш сеанс кажется проигнорированным, проблема может заключаться в том, что Symfony считает, что ваш пользователь изменился.Это может быть вызвано ошибочной (де) сериализацией или сравнением.

По умолчанию Symfony использует сериализованные результаты getPassword(), getUsername() и getSalt() из сеанса для сравнения с пользователем, предоставленнымпоставщик пользователя (например, база данных).Если какое-либо из этих значений изменится, вы выйдете из системы (см. https://symfony.com/doc/current/security/user_provider.html#understanding-how-users-are-refreshed-from-the-session).

Таким образом, вы должны убедиться, что пользователь, предоставленный вашей базой данных, является правильным и соответствует десериализованному пользователю из сеансаУбедитесь, что соответствующие поля правильно сериализованы. Если вы реализуете интерфейс Serializable, убедитесь, что ваш метод serialize() соответствует вашему deserialize(). Если вы реализуете EquatableInterface, убедитесь, что ваш метод isEqualTo() работает правильно.из этих интерфейсов не являются обязательными, поэтому вы можете удалить их для целей отладки.

2 голосов
/ 09 июля 2019

Произошло со мной год назад, аутентификация прошла успешно, перенаправлена ​​и зарегистрирована как анонимная. Заставь меня хотеть разбить мою голову о стены. Проблема, которая у меня была тогда, заключалась в том, что я создал пользователя в соответствии со старым курсом из KnpUniversity, и он не реализовал EquatableInterface и метод isEqualTo. Надеюсь, это сработает для вас.

Убедитесь, что ваш пользовательский объект реализует EquatableInterface

namespace App\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;

    class User implements UserInterface, EquatableInterface
{
    private $username;
    private $password;
    private $salt;
    private $roles;

    public function __construct($username, $password, $salt, array $roles)
    {
        $this->username = $username;
        $this->password = $password;
        $this->salt = $salt;
        $this->roles = $roles;
    }

    // your setters, getters and whatever ...

    public function isEqualTo(UserInterface $user)
    {
        if (!$user instanceof WebserviceUser) {
            return false;
        }

        if ($this->password !== $user->getPassword()) {
            return false;
        }

        if ($this->salt !== $user->getSalt()) {
            return false;
        }

        if ($this->username !== $user->getUsername()) {
            return false;
        }

        return true;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...