J'ai construit un formulaire de connexion en suivant ce document de configuration de connexion .
Cela fonctionne bien sur localhost mais pas sur le serveur de production .
Itinéraire correspondant "easyadmin
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; } }
L'utilisateur a été rechargé à partir d'un fournisseur d'utilisateurs
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; }*/ }
Accès refusé et retour à l'URL de connexion
# 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";}
_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";}
_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";}
access_control: - { path: ^/odelices_admin, roles: ROLE_USER}
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: { }
php bin/console debug:config security
sortie de php bin/console debug:config security
// 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
Comme @Arno l'a commenté, j'ai édité framework.yaml
pour enregistrer les sessions dans le répertoire var/
et je peux vérifier que cette étape fonctionne sans problèmes d'autorisations, chaque fois que je frappe le formulaire de connexion, un fichier sess_ est écrit.
Cela vaut la peine de dire que si je commente:
// 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'); } }
Je peux accéder au backoffice.
Alors maintenant, les sessions sont enregistrées dans var / sessions / prod.
sudo rm -r var/sessions/prod/sess_*
J'ouvre Chrome et l'url, il définit un cookie PHPSSID avec la même valeur qu'un premier fichier sess_xyz:
admin: path: /backoffice controller: EasyCorp\Bundle\EasyAdminBundle\Controller\EasyAdminController
Je vais à la page de connexion. Nouvelle valeur PHPSSID associée à un nouveau fichier sess_xyz:
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
Je me connecte avec des valeurs correctes. Cela crée 3 nouveaux fichiers ssid_xyz.
### 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"} []
### 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"} []
Debian Stretch, Nginx + Varnish : Nginx gère 443 requêtes, les transmet à Varnish en tant que proxy de cache, qui fournit des objets mis en cache ou transmet des requêtes au backend nginx sur le port 8083. Cela fonctionne comme un charme pour une autre application avec une logique de connexion similaire (la seule différence est le buggy redirigé vers easyadmin au lieu d'un administrateur personnalisé), donc je ne pense pas que cela soit lié à la pile.
vhost
### 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"} []
Cela pourrait-il être lié aux autorisations sur certains répertoires? HTTPS? EasyAdmin? Comment puis-je m'assurer que le jeton de sécurité a été stocké dans la session, même s'il est enregistré comme stocké? J'ai également essayé de changer access_control en rôle ROLE_USER afin que tout utilisateur authentifié puisse y accéder. En aucune façon.
Toute aide est vraiment appréciée.
4 Réponses :
Cela m'est arrivé il y a un an, authentification réussie, redirection et connexion anonyme. Donne-moi envie de me fracasser la tête contre les murs. Le problème que j'avais à l'époque était que j'ai créé l'utilisateur selon un ancien cours de KnpUniversity et qu'il n'a pas implémenté EquatableInterface et la méthode isEqualTo. J'espère que cela fonctionnera pour vous.
Assurez-vous que votre entité utilisateur implémente 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; } }
Merci Yoann. Cela ne change pas le comportement. : - ((je vais publier l'entité utilisateur
Vous vous demandez peut-être: j'ai effectué cette vérification lors de ma tentative d'implémentation d'EquatableInterface if ($this->email !== $user->getUsername())
car getUsername renvoie l'email tel que défini dans le fournisseur security.yaml ... cela fonctionne dans localhost, pas en prod
c'est étrange et peut-être lié à votre problème
Pour autant que je sache, par défaut, l'utilisateur est actualisé en comparant le dernier sérialisé avec le courant, en utilisant getSalt()
, getPassword()
et getUsername()
de l'entité utilisateur. getUsername
n'est pas getName()
, il doit renvoyer une valeur unique, et vous définissez laquelle dans la propriété d'entité security.yaml -> fournisseurs. tu n'es pas d'accord? Votre implémentation fonctionne bien avec ma configuration, mais il n'y avait aucune raison d'ajouter cette vérification dans ma configuration si basique. Quoi qu'il en soit, grâce à vous, j'ai appris une nouvelle façon de personnaliser cette étape!
Cela finit par dire que la configuration de Varnish était défectueuse.
J'ai complètement oublié que je devais spécifier n'importe quel modèle de backoffice tel que /admin/ , /backoffice/
et plus pour ne pas être mis en cache par le proxy , mais au lieu de cela directement transmis au backend .
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); } #Â ...
Cela était déjà configuré pour l'autre application symfony que je mentionne dans la question, et pour plusieurs sites Web Drupal. Au moins, cela m'a obligé à creuser profondément dans le processus d'authentification des utilisateurs Symfony 4 , et comment le déboguer! Peut-être que cet article de débogage étape par étape aidera d'autres lecteurs?!
Voici donc mes commentaires d'une manière plus structurée, afin que cela puisse aider quelqu'un d'autre ayant des problèmes d'authentification dans Symfony.
Par défaut, chaque session est enregistrée sous forme de fichier avec le nom sess_<id>
dans <project_dir>/var/cache/<env>/sessions
ou comme défini par save_path
dans votre php.ini
si framework.session.handler
est défini sur null
. Configurez votre répertoire de session de manière explicite et assurez-vous qu'un fichier de session est créé lorsque vous vous connectez. Sinon, vérifiez les autorisations pour ce dossier.
_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";}
Cf. https://symfony.com/doc/current/session.html#configuration
Lorsque vous vous connectez, une session avec un nouvel ID doit être créée. Vérifiez le contenu du fichier. Il doit contenir votre utilisateur sérialisé sous le nom du pare-feu (par exemple, main), y compris votre identifiant (par exemple, email) et votre (vos) rôle (s) utilisateur (par exemple ROLE_USER). Un problème ici peut être causé par une authentification, une configuration de sécurité ou une sérialisation incorrectes.
# 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%'
Vérifiez qu'un cookie avec le même identifiant est défini dans votre navigateur lors de la connexion. Le nom du cookie est défini par session.name
dans votre php.ini
, par défaut c'est PHPSESSID
. Il doit être envoyé avec chaque demande que vous faites (par exemple, Cookie: PHPSESSID=lpcf79ff8jdv2iigsgvepnr9bb
). Si la session correcte existe, mais que vous avez un cookie différent dans votre navigateur, vous avez peut-être été immédiatement déconnecté après une redirection réussie.
L'ID de session ne doit changer que lorsque votre utilisateur change (par exemple lors de la connexion et de la déconnexion). S'il change après des requêtes normales (par exemple, vous êtes immédiatement déconnecté) ou si votre session semble être ignorée, le problème peut être que Symfony considère que votre utilisateur a changé. Cela peut être causé par une (dé) sérialisation ou une comparaison défectueuse.
Par défaut, Symfony utilise les résultats sérialisés de getPassword()
, getUsername()
et getSalt()
de la session pour les comparer avec l'utilisateur fourni par le fournisseur de l'utilisateur (par exemple la base de données). Si l'une de ces valeurs change, vous êtes déconnecté (cf. https://symfony.com/doc/current/security/user_provider.html#understanding-how-users-are-refreshed-from-the-session ).
Ainsi, vous devez vous assurer que l'utilisateur fourni par exemple par votre base de données est correct et correspond à l'utilisateur désérialisé de la session. Assurez-vous que les champs pertinents sont correctement sérialisés. Si vous implémentez l'interface Serializable
, assurez-vous que votre méthode serialize()
correspond à votre unserialize()
. Si vous implémentez EquatableInterface
, assurez-vous que votre méthode isEqualTo()
fonctionne correctement. Cependant, ces deux interfaces sont facultatives, vous pouvez donc envisager de les supprimer à des fins de débogage.
Le "isEqualTo ()" et les méthodes de sérialisation ont fonctionné pour moi, merci!
J'ai eu le même symptôme que celui décrit par l'OP mais dans une application Symfony 5.1 et en utilisant ma propre entité utilisateur existante. Il s'avère que le problème est que je n'ai pas implémenté \ Serializable sur mon entité utilisateur et les 2 méthodes requises:
public function serialize() { return serialize(array( $this->id, $this->username, $this->password, // see section on salt below // $this->salt, )); } /** @see \Serializable::unserialize() */ public function unserialize($serialized) { list ( $this->id, $this->username, $this->password, // see section on salt below // $this->salt ) = unserialize($serialized, array('allowed_classes' => false)); }
Une fois que cela a été corrigé, l'application a pu rester connectée à la fois dans les environnements de développement et de production, et avec et sans l'option "Se souvenir de moi". La logique derrière cela est expliquée sur le site officiel .
Pouvez-vous montrer utiliser votre configuration en utilisant le débogage php bin / console: config security
Avez-vous effacé le cache sur le serveur après le téléchargement?
Je viens de
php bin/console debug:config security
output. Oui, je recherche le problème depuis hier soir et j'ai vidé le cache environ 100 fois, vérifié les problèmes d'autorisations ...Utilisez-vous les paramètres par défaut pour l'enregistrement des sessions (configurés sous framework.session)? Si tel est le cas, les sessions sont enregistrées en tant que fichiers et cela peut certainement être un problème d'autorisation. Par défaut, ils doivent être enregistrés dans un dossier "sessions" dans votre répertoire de cache, mais vous pouvez changer cela comme décrit ici: symfony.com/doc/3.4/session/sessions_directory.html . Vous pouvez peut-être essayer d'accorder des autorisations au répertoire 777. Il devrait créer un fichier par session au format "sess_ <id>" avec l'utilisateur sérialisé à l'intérieur.
@ArnoHilke Merci beaucoup pour cet indice. Eh bien, je suis passé à 4.3 doc puis j'ai changé ma configuration pour enregistrer explicitement les sessions dans var dir, et jusqu'à présent, la session y est écrite, donc malheureusement ce n'est pas le point de blocage: ((
Qu'en est-il du fait qu'une nouvelle valeur est donnée au ssid chaque fois que je frappe une URL (page de connexion ou non)? Est-ce un comportement normal ???
@Kojo L'ID de session doit changer à chaque fois que votre niveau d'authentification change, c'est-à-dire lors de la connexion et de la déconnexion, mais pas sur les requêtes normales. Une raison pourrait être que votre utilisateur change ou est détecté comme modifié, par exemple à cause d'une (dé) sérialisation défectueuse. Vous pouvez également vérifier 1) si une session appropriée est créée lorsque vous vous connectez (vérifiez le contenu du fichier pour un utilisateur avec une adresse e-mail et un rôle appropriés) et 2) si le cookie est correctement défini et envoyé avec cet ID de session sur votre client .
@ArnoHilke merci encore! J'ai édité le message avec tout le comportement. S'il vous plaît jeter un oeil, oui les cookies sont définis concernant les fichiers ssid, mais chaque fois que la redirection est effectuée, retour au début ... Je dois assister à des réunions d'équipe cet après-midi, je reviendrai après ... Je ne sais vraiment pas Que penser :-((
pouvons-nous voir votre entité utilisateur s'il vous plaît?
Veuillez également vérifier qu'il n'y a pas d'option
stateless: true
sous votre pare-feu. Cela bloquera le démarrage de session pour l'utilisateur, et tous resteront anonymes après une authentification réussie.