REST API enregistrer lastAccess

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Je réalise une API REST avec Symfony 3, j'ai mis en place une authentification Basic qui fonctionne bien, cependant je souhaiterai enregistrer le dernier accès de l'utilisateur et j'ignore comment faire.

J'utilise les paramètres standard de Symfony, j'ai donc créé une entité provider. J'ai un moment penser à l'injection de dépendance mais c'est une entité et non un service et je ne pense pas que j'ai vraiment le droit de faire sa (ni même si c'est techniquement réalisable).

Du coup je suis coincé… je souhaiterai donc à chaque fois que le visiteur accède à une ressource mettre à jour mon attribut lastAccess sauf que j'ignore comment faire :(

A tout hasard voici ma configuration:

security.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
security:
    encoders:
        AppBundle\Entity\TokenAuthorization: plaintext # juste le temps de faire mes tests sa ;)

    providers:
        api_provider:
            entity:
                class:    AppBundle:TokenAuthorization
                property: token

    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        login: #honnêtement j'suis pas sur pour lui, d'autant que je veux accorder que le post pour les annon)
            pattern: ^/api/useraccounts/tokens
            anonymous: true

        api:
            pattern: ^/api/
            provider: api_provider
            stateless: true
            anonymous: ~
            http_basic:
               realm: "Auth API"

    access_control:
        - { path: ^/api/useraccounts/tokens, roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [POST] }
        - { path: ^/api/, role: [ROLE_API_USER, ROLE_API_TERMINAL] }

J'ai fais une recherche sur le net, je remarque pas mal de solution dans le cas d'un formulaire de login, cependant ce n'est pas le dernier login que je souhaite enregistrer mais le dernier accès.

Merci d'avance pour votre aide.
Cordialement La source

+0 -0

Salut La source,

Tu peux utiliser les événements du système de sécurité de Symfony pour mettre à jour ton champs lastAccess.

Avec un listener sur l'événement AuthenticationEvents::AUTHENTICATION_SUCCESS, tu peux effectuer ta mise à jour à chaque connexion de l'utilisateur. En stateless, chaque requête va nécessité une nouvelle authentification. Donc chaque accès va forcément entrainer un login.

Par contre, tu utilises une authentification basic en mode stateless. Tu demandes donc à chaque requête à ton client de fournir son login et son mot de passe.

Mais de manière générale, si tu veux effectuer une opération à chaque accès, tu peux utiliser les events du kernel de Symfony comme KernelEvents::REQUEST qui est déclenchée pour toutes les requêtes du client. Par contre, tu devras porter une attention particulière à la priorité des EventListener si tu veux accéder à certaines informations comme l'utilisateur actuellement connecté, etc.

Cordialement.

Merci pour ta réponse,

Cependant je galère à mettre en place la solution :(
J'ai définit un nouveau service et un nouveau listener

services.yml

1
2
3
4
5
6
7
8
services:
    authentication_listener:
        class: AppBundle\Listener\AuthenticationListener
        arguments:
            - "@security.token_storage"
            - "@doctrine.orm.entity_manager"
        tags:
            - {name: kernel.event_listener, event: security.authentication.success, method: loginSuccess}

AuthenticationListener.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
class AuthenticationListener
{
    /**
     * @var TokenAuthorization
     */
    private $token;

    /**
     * @var EntityManager
     */
    private $em;


    public function __construct(TokenStorage $tokenStorage, EntityManager $em)
    {
        echo get_class($tokenStorage->getToken());
        $this->em = $em;
    }

    public function loginSuccess()
    {
        //$this->token->login();
        //$this->em->flush();
    }
}

Le problème est que si je tente d'invoquer ma méthode login j'ai droit à une erreur comme quoi getUser() se fait sur une valeur null.

Le résultat de mon echo me renvoie AuthenticationListener ce qui me rend perplexe… j'ai fais une recherche et je suis tombé sur une réponse sur stackoverflow disant que si c'était null c'était qu'on était pas identifié… du coup je pige pas :(

+0 -0

L'attribut s'appelle tokenStorage mais dans ton constructeur tu utilises token. D'ailleurs le code que tu as posté devrait plutôt lever une erreur fatale puisque l'attribut tokenStorage est nul (et donc n'a pas de méthode getToken).

Vu que tu es parti sur l'événement , il est utile de rappeler qu'il sera déclenché dans tous les cas de figures où l'utilisateur est considéré comme connecté.

When a provider authenticates the user, a security.authentication.success event is dispatched. But beware - this event will fire, for example, on every request if you have session-based authentication. See security.interactive_login below if you need to do something when a user actually logs in.

Documentation Symfony sur les événements d'authentification

J'ai un peu modifier la classe que j'ai postée car mes tests se trouvaient dans mon constructeur et je testais direct les paramètres… du coup oui comme c'est là c'est complètement faux mais le résultat est bien là.

Du coup, oui c'est que je souhaite faire mais get_class($tokenStorage->getToken()) (dans le constructeur) rembale AuthenticationListener.

+0 -0

IL y a deux problèmes dans ton approche.

  1. Dans le constructeur le tokenStorage est vide puisque Symfony instancie d'abord toutes tes classes avant de commencer le mécanisme d'authentification. Du coup, $tokenStorage->getToken()=nul et get_class(null) = get_class(), le nom de ta classe AuthenticationListener.
  2. L’événement déclenché par Symfony contient déjà le token. Le listener est appelé avec un événement du type AuthenticationEvent qui contient le token que tu veux récupérer.

Tu devrais plutôt voir le comportement des listeners de Symfony en détail afin de profiter au maximum des possibilités qu'ils peuvent t'apporter.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte