Laravel 8

Créer un blog – le RGPD

Nous avons dans le précédent article codé le profil de l’utilisateur. Dans un commentaire récent Braice m’a proposé de traiter le sujet du RGPD. C’est un sujet qu’il est nécessaire de prendre en compte dès qu’on doit recueillir et mémoriser des données personnelles. Le RGPD (Règlement Général sur la Protection des Données, mais ça fait GDPR en anglais) est une réglementation européenne qui a pour but d’encadrer strictement le traitement des données des personnes physiques. On peut se demander ce qu’est une donnée personnelle, et en fait c’est assez vaste : nom, adresse, email, téléphone, en fait toute donnée susceptible d’identifier une personne directement ou indirectement (par exemple le fait de croiser deux informations non pertinentes peut le devenir). Pour tout savoir sur le sujet je ne peux que vous conseiller le site officiel de la CNIL.

On peut se demander dans le cas de notre blog ce qu’il convient de mettre en place pour respecter ce règlement.  » Le règlement général sur la protection des données (RGPD) impose une information concise, transparente, compréhensible et aisément accessible des personnes concernées. « . On doit donc faire preuve de transparence : pourquoi on collecte des données, ce qu’on va en faire, combien de temps on les conserve, qui y a accès, et seront-elles accessibles ? Lorsqu’une personne s’inscrit sur le blog on a une collecte directe de données et on doit donc fournir toutes les informations nécessaires lors de cette collecte. Le plus simple est de créer une page spécifique qui explique tout (responsable du traitement, finalité, base légale, durée de conservation, droit d’accès et de modification…) mais on doit en faire référence dans le formulaire, ce que nous n’avons pas fait.

Quand on recueille des informations personnelles il faut le consentement de la personne, et celui-ci doit être « libre, spécifique, éclairé et univoque ». Comment y parvenir ? Lisons le texte officiel : « Le consentement devrait être donné par un acte positif clair par lequel la personne concernée manifeste de façon libre, spécifique, éclairée et univoque son accord au traitement des données à caractère personnel la concernant, … Cela pourrait se faire notamment en cochant une case lors de la consultation d’un site internet« . Dans la pratique j’ai opté pour une case à cocher. La soumission d’un formulaire est impossible tant que la case n’est pas cochée. Le texte associé à la case exprime clairement la nature du consentement et renvoie à une page qui explicite tout.

Pour ce qui concerne les cookies ceux utilisés pour le blog sont exemptés de consentement parce qu’ils sont « destinés à l’authentification auprès d’un service, y compris ceux visant à assurer la sécurité du mécanisme d’authentification, par exemple en limitant les tentatives d’accès robotisées ou inattendues « . On n’a donc pas à mettre en place une alerte spécifique.

Vous pouvez télécharger le code final de cet article ici.

L’enregistrement

Pour le moment notre formulaire d’enregistrement se présente ainsi :

Un composant pour la case à cocher

On va ajouter une case à cocher pour le consentement. Comme on aura aussi à traiter le formulaire de contact on crée un composant pour la case à cocher :

On le code ainsi :

<label class="h-add-bottom">
    <input 
        id="rgpd" 
        type="checkbox" 
        name="rgpd"
        {{ old('rgpd') ? 'checked' : '' }}> 
    <span class="label-text">@lang("I have read and accept the site's privacy policy.")</span>
</label>

On ajoute la traduction dans resources/lang/fr.json :

"I have read and accept the site's privacy policy.": "J’ai lu et accepte la politique de confidentialité du site.",

On doit insérer ce composant dans la vue auth.register juste avant le bouton de soumission :

<!-- RGPD -->
<x-auth.rgpd-checkbox />

<x-auth.submit title="Register" />

Il ne reste plus qu’à le faire fonctionner…

Un composant pour le script

Là aussi pour rendre le script facilement réutilisable on crée un autre composant :

Avec un peu de Javascript :

<script>
    const change = () => {
        if(rgpd.checked) {
            submit.removeAttribute('disabled');
            submit.style.cursor = 'pointer';                  
        } else {
            submit.setAttribute('disabled', true);
            submit.style.cursor = 'not-allowed';   
        }
    }

    document.addEventListener('DOMContentLoaded', () => {
        const rgpd = document.getElementById('rgpd');
        const submit = document.getElementById('submit');
        change();
        rgpd.addEventListener('click', () => change());
    });
</script>

On l’ajoute en bas de la vue auth.register :

@section('scripts')
    <x-auth.rgpd-script />
@endsection

Pour facilement accéder au bouton de soumission on ajoute un identifiant dans le composant auth.submit :

@props(['title'])

<input 
    id="submit" 
    class="btn--primary h-full-width" 
    type="submit" 
    value="@lang($title)">

Fonctionnement

Au chargement le bouton est inactif (l’icône de la souris a été adapté) :

Quand on coche la case le bouton devient actif et l’icône change :

Le contact

Pour le moment notre formulaire de contact se présente ainsi pour un utilisateur non authentifié :

On ajoute les composants qu’on a créé précédemment dans la vue front.contact :

                          <br>
                          
                          @if(Auth::guest())
                            <x-auth.rgpd-checkbox />
                          @endif

                          <x-auth.submit title="Send" />

                      </fieldset>
                  </form>

                </div>
            </div>


        </div>
    </div>

@endsection

@section('scripts')
    @if(Auth::guest())
        <x-auth.rgpd-script />    
    @endif
@endsection

On introduit cette fonctionnalité que si on a affaire à un utilisateur non authentifié, sinon on a déjà les données personnelles. On bénéficie maintenant exactement du même fonctionnement que pour le formulaire d’enregistrement :

Le profil

On a déjà créé un formulaire de profil où l’utilisateur authentifié peut lire et modifier ses données personnelles. On va ajouter la possibilité de supprimer le compte. Évidemment ça aura pour conséquence la suppression corrélative des éventuelles données liées : articles et commentaires.

Le contrôleur RegisteredUserController

On ajoute une méthode dans le contrôleur RegisteredUserController :

public function destroy(Request $request)
{
    $request->user()->delete();

    return response()->json();
}

On va y accéder en Ajax, on se contente de supprimer le compte et de renvoyer un réponse JSON.

La route

On ajoute une route :

// Profile
Route::middleware(['auth', 'password.confirm'])->group(function () {
    ...
    Route::name('deleteAccount')->delete('profile/delete',  [RegisteredUserController::class, 'destroy']);
});

On la prévoit dans le groupe protégé du profil.

La vue auth.profile

Dans la vue auth.profile on ajoute la bouton et le script :

                <x-auth.submit title="Save" />

                <a id="delete" href="{{ route('deleteAccount') }}" class="btn btn--primary h-full-width" style="background: crimson;">@lang('Delete account')</a>
                 
            </form>
        </div>
    </div>

@endsection

@section('scripts')

    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>

    <script>

        // Variables
        const headers = {
            'X-CSRF-TOKEN': '{{ csrf_token() }}', 
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }

        // Delete account
        const deleteAccount = async e => {              
            e.preventDefault();
            Swal.fire({
                title: '@lang('Really delete your account?')',
                icon: 'warning',
                showCancelButton: true,
                confirmButtonColor: '#DD6B55',
                confirmButtonText: '@lang('Yes')',
                cancelButtonText: '@lang('No')',
                preConfirm: () => {
                    return fetch(e.target.getAttribute('href'), { 
                        method: 'DELETE',
                        headers: headers
                    })
                    .then(response => {
                        if (response.ok) {
                            document.location.reload();
                        } else {
                            Swal.fire({
                                icon: 'error',
                                title: '@lang('Whoops!')',
                                text: '@lang('Something went wrong!')'
                            });  
                        }
                    });
                }
            });
        }

        document.getElementById('delete').addEventListener('click', e => deleteAccount(e));

    </script>

@endsection

On ajoute les traductions dans resources/lang/fr.json :

"Delete account": "Supprimer mon compte",

...

"Really delete your account?": "Vraiment supprimer votre compte ?",

On se retrouve avec un bouton supplémentaire :

Par sécurité on présente une fenêtre de confirmation :

En cas de suppression effective on recharge la page et, comme l’utilisateur n’est plus authentifié, le middleware renvoie sur la page de connexion.

Conclusion

Voilà maintenant on devrait être en conformité avec le RGPD !

Print Friendly, PDF & Email

6 commentaires

Laisser un commentaire