Exemple Dossier Projet
Exemple Dossier Projet
Marie Germain
Je tiens à remercier mes collègues de formation avec qui j'ai pu échanger autour de mon
projet et qui m'ont apporté leurs conseils quand j'en avais besoin, ainsi que mon formateur
pour sa disponibilité, son soutien, ainsi que pour les conseils techniques qu'il m'apporte tout
au long de mon stage.
2
Sommaire
Remerciements........................................................................................................................................................2
Sommaire................................................................................................................................................................. 3
Introduction............................................................................................................................................................. 4
1. Compétences du référentiel couvertes par le projet........................................................................4
a. Développer la partie front-end d’une application web ou web mobile en intégrant les
recommandations de sécurité.............................................................................................................. 4
b. Développer la partie back-end d’une application web ou web mobile en intégrant les
recommandations de sécurité.............................................................................................................. 4
2. Résumé du projet..............................................................................................................................5
3. Environnement humain et technique............................................................................................... 6
a. Environnement humain.................................................................................................................... 6
b. Environnement technique................................................................................................................ 6
Le projet de stage................................................................................................................................................... 7
1. Le cahier des charges........................................................................................................................7
2. Spécifications techniques..................................................................................................................8
La réalisation du projet.......................................................................................................................................... 9
1. Conception de la base de données................................................................................................... 9
2. Développement de l’API................................................................................................................. 11
a. Installation...................................................................................................................................... 11
b. Initialisation du projet.....................................................................................................................12
c. Développement de la base de données.......................................................................................... 13
d. Développement des routers et controllers.....................................................................................14
3. Développement de la partie front-end........................................................................................... 16
a. Mise en place de l’environnement de développement.................................................................. 16
b. La navigation au sein de l’application............................................................................................. 16
c. Les fonts.......................................................................................................................................... 18
d. Les contextes.................................................................................................................................. 19
e. Écrans développés.......................................................................................................................... 20
Fonctionnalité la plus représentative: L’authentification.................................................................................24
1. Jeu d’essai....................................................................................................................................... 24
2. Recherches anglophones sur le JWT...............................................................................................28
Conclusion............................................................................................................................................................. 29
Annexes.................................................................................................................................................................. 30
3
Introduction
L'application mobile doit être disponible sur Android et iOS, d'où le choix de développer en
React Native qui permet un développement cross-plateform. Malgré cela, il est nécessaire
d'effectuer des ajustements suivant le système d'exploitation. Elle doit pouvoir proposer une
expérience utilisateur similaire quelle que soit la taille de l'écran. J'ai donc fait en sorte que
l'interface s'adapte aux différentes tailles de mobiles.
La partie front fait appel à une API qui renvoie les données d'une base de données
relationnelle que j'ai pensée et développée. Concernant l'API, je l'ai développée en Node.js,
grâce au framework Express.js. De plus, elle utilise Knex.js, un query builder qui permet de
développer facilement une base de données en JavaScript, et Objection.js, un ORM (Object-
Relational Mapping) pour Node.js.
4
2. Résumé du projet
Dans le cadre de ma formation Développeur Web – Web Mobile, je réalise un stage de 4
mois qui a débuté le 17 août 2020, et ce jusqu’au 17 décembre 2020, dans le cadre du projet
« Skimtrack ».
Ma maître de stage, Madame Béland Laure porte ce projet depuis mars 2020 au sein d’un
incubateur.
Le projet Skimtrack est une application mobile de parcours sportif. L'utilisateur choisit un
parcours en plein air et accède à du contenu vidéo disponible à chaque point d'intérêt sur
une carte. Ces vidéos courtes montrent des coachs présentant les exercices à pratiquer sur le
lieu. Le contenu Skimtrack est accessible via l'achat de forfait mensuel directement dans
l'application.
Le déploiement d’une première version de l’application avec les premières fonctionnalités est
prévu au printemps 2021. Mon rôle au sein du projet est de procéder à l’ensemble du
développement de l’application mobile : React Native pour le front, Node.js et Express pour
le développement de l’API, ainsi que la mise en place de la base de données relationnelle.
Étant la seule développeuse, je réalise ce stage en totale autonomie au sein de mon équipe.
Cela m’a permis de mettre en pratique les compétences acquises lors de la formation, mais
également d’en gagner de nouvelles très rapidement en me référant aux différentes
documentations et forums dédiés, que j’ai pu appliquer au projet, qui était au début du stage,
un véritable challenge pour moi.
5
3. Environnement humain et technique
a. Environnement humain
Lorsque j'ai rejoint l'équipe Skimtrack, elle n'était jusqu'alors composée que de Madame
Béland.
Madame Béland est l'initiatrice du projet Skimtrack. Elle s'occupe plutôt de la partie
technique, de trouver le meilleur moyen d’aborder les différentes fonctionnalités de
l’application, de trouver des partenaires dans le milieu du sport afin de donner de la visibilité
au projet. Bien qu'elle ne soit pas formée sur les technologies que j'utilise, son expérience
dans le développement informatique m'incite à prendre du recul lorsque je rencontre un
obstacle et m'aide parfois dans le raisonnement qui m'amène à trouver la solution.
Début septembre, nous avons été rejointes par Emma, stagiaire UX designer, issue de la
formation UX dispensée au sein du Village du Code à Bordeaux. Le travail d’Emma a eu un
impact fort sur mon stage. Grâce à elle, j'ai pris conscience de l'importance de l'UX au sein
d'un projet, j'ai appris les différentes étapes d'un parcours UX, en participant notamment aux
différentes étapes de la réflexion autour d'une fonctionnalité ciblée.
Puis, début novembre, nous avons été rejointes par Thomas, étudiant en licence
professionnelle Création et Diffusion Audiovisuelle sur Internet. Il s’occupe entièrement de la
création des vidéos qui auront une identité « Skimtrack ».
b. Environnement technique
Je travaille sur un ordinateur portable car j'ai besoin d'être mobile. En effet, je me rends à
l’incubateur 2 jours par semaine où je travaille avec les membres de l'équipe. Les 3 jours
restants je travaille au sein de l'espace de coworking de la Station à Bordeaux avec d’autres
apprentis développeurs, qui sont également en télétravail. C'est l'occasion pour moi
d'échanger avec eux, d'évoquer les obstacles auxquels je suis confrontée et parfois trouver la
solution à travers ces échanges.
6
Le projet de stage
Le cahier des charges de l'application mobile à développer était déjà très complet à mon
arrivée en stage. Les fonctionnalités se sont allégées au fur et à mesure de l’avancement des
travaux UX (maquettes, interview, mises à jour).
Nous avons donc travaillé en mode agile avec une méthodologie Scrum allégée. J’ai ainsi
adapté l’avancement du développement en fonction des fonctionnalités et écrans validés au
fur et à mesure.
A son arrivée dans l'application, l'utilisateur arrive sur un écran d'onBoarding, où est expliqué
le principe de l'application. Il peut ensuite choisir de s'inscrire ou de s'authentifier.
L'utilisateur accède à un mode "parcours libre", il est géolocalisé sur une carte, où
apparaissent des marqueurs, indiquant les points d'intérêt se trouvant à proximité.
L'utilisateur peut choisir d'accéder à l'onglet "parcours guidés", où il trouvera la liste des
parcours à proximité, présentés sous forme d'une liste scrollable de vignettes, qui
contiennent diverses informations à propos de chaque parcours.
Si l'utilisateur est abonné, il peut débuter un parcours, pendant lequel il sera guidé de point
d'intérêt en point d'intérêt, grâce à un système de GPS. Chaque point d'intérêt possède une
ou plusieurs vidéos d’exercices de renforcement musculaire.
A la fin de chaque parcours, l'utilisateur peut laisser un commentaire et peut partager son
expérience sur les réseaux sociaux.
L'utilisateur a également accès son profil utilisateur, où il peut ajouter un avatar, modifier ses
informations personnelles, visualiser ses parcours marqués comme favoris ou se déconnecter.
7
L'utilisateur peut activer d'autres fonctionnalités :
Activer les notifications afin d'être informé lorsqu'il se trouve près d'un point d'intérêt
Activer ou non le tracking d’activité cardiaque grâce à un bracelet connecté vendu
séparément.
2. Spécifications techniques
Partie Front :
- React Native : framework gratuit et Open Source créé par Facebook, basé sur
la librairie JavaScript React. Il permet le développement d'applications cross-
plateforms et utilise les composants mobiles natifs.
Partie Back :
- Node.js : un environnement bas niveau permettant l’exécution de code
JavaScript côté serveur. Grâce à son fonctionnement non bloquant, il permet
de concevoir des applications en réseau performantes, telles qu’un serveur
web ou une API.
- Express.js : framework qui permet de construire des applications web basées
sur Node.js, pratique pour le développement de serveur. Il permet une
création d'API robuste de manière simple et rapide.
- Knex.js : SQL builder qui permet de créer une base de données, de la modifier
et d'écrire des requêtes avec une syntaxe objet.
- Objection.js : ORM (Object Relational Mapping) qui fonctionne avec Knex.js.
Son système de modèles permet une description précise des données
attendues.
8
La réalisation du projet
1. Conception de la base de données
Avec Madame Béland, nous avons commencé par lister toutes les données que nous avions
besoin de stocker. Nous nous sommes posées la question suivante : quelles entités avons-
nous au sein de l'application ? Par exemple, nous avons des parcours. Un parcours est
caractérisé par un id, un nom, une description, une ou plusieurs vidéos d’exercice appelées
capsules, un potentiel coût supplémentaire si dans un terrain privé et l'id de l'utilisateur qui a
ajouté le parcours. Une fois toutes nos entités définies, nous avons utilisé la méthode Merise,
méthode d'analyse et de conception de systèmes d'informations, notamment de bases de
données.
Nous avons commencé par établir le Modèle Conceptuel de Données (MCD). Cette étape
consiste à établir des relations entre les différentes entités, en précisant les cardinalités.
9
Une fois ces dernières établies, nous avons pu passer à l’élaboration du Modèle Logique de
Données (MLD). Chaque entité devient une table et leur identifiant devient la clé primaire de
la table. Pour les relations ayant des cardinalités *,1 — *,n la clé primaire de la table côté *,n
devient une clé étrangère de la table côté *,1 créant ainsi la relation entre les tables. Les
relations "Many to Many", représentées par des cardinalités *,n — *,n , génèrent une nouvelle
table qui comportera 2 champs, correspondant aux id de chacune des 2 entités.
10
Ensuite, nous avons pu élaborer le Modèle Physique de Données (MPD), qui consiste à
préciser le type et les possibles restrictions appliquées pour chaque champ qui compose les
tables.
Une fois l'élaboration de la structure de la base de données terminée, j'ai procédé au
développement de la partie back, afin de générer dans un premier temps, la base de données.
2. Développement de l’API
a. Installation
J'ai donc créé un dossier dans lequel j'ai lancé la commande npm init qui initialise un projet
en créant le fichier package.json, qui contient les informations du projet : le nom, la version,
la description, le fichier qui sera le point d'entrée, les commandes qui serviront aux tests, le
repository git associé, des mots-clés, l'auteur et la licence.
Node.js étant déjà installé sur mon ordinateur, j'ai pu passer à l'installation d'Express, grâce à
la commande : npm install express --save.
11
Puis de la librairie correspondant à la base de données :
npm install mysql2 –save
b. Initialisation du projet
Une fois l'installation de toutes les librairies effectuée, j'ai créé la base de données locale
"Skimtrack" en utilisant phpMyAdmin. J'ai également créé un nouveau compte utilisateur, en
lui attribuant tous les privilèges sur cette base de données.
Dans le dossier du projet, j'ai créé un fichier .env qui contient notamment les variables
nécessaires à la connexion à la base de données : le host, l'utilisateur, le mot de passe, le nom
de la base de données, ainsi que le port utilisé. L'installation de la libraire « dotenv » grâce à
la commande : npm install dotenv puis son import dans le fichier server.js (qui sera le point
d'entrée) nous permet d'accéder aux variables situées dans le fichier .env depuis n'importe où,
grâce à : process.env.[nom_de_la_variable].
Avec la commande npx knex init, je peux ensuite générer le fichier knexfile.js, qui contiendra
les paramètres nécessaires à la connexion à la base de données pendant le développement.
Fichier knexfile.js
Ensuite, il me faut importer Express, Knex et Objection dans le fichier server.js puis d’indiquer
le port :
12
Le serveur est prêt à être lancé, grâce à la commande node server.js.
13
Fichier de migration permettant la création de la table « course »
J'ai créé un dernier fichier qui vient modifier les tables afin d'ajouter les clés étrangères
comme suit :
Une fois tous les fichiers crées, j’ai mis à jour la base de données en appliquant tous les
fichiers de migrations qui n'ont pas encore été appliqués, grâce à la commande npx knex
migrate:latest. Afin de gagner du temps, j'ai exporté le fichier SQL de la base de données de
l'application web, que j'ai modifié afin qu'il corresponde à la nouvelle architecture de ma
base de données, que j'ai importé dans celle-ci, afin d'avoir des données fictives à exploiter
lors du développement de l'API.
Par exemple, voici le controller courses.js qui contient toutes les requêtes concernant les
parcours. La fonction getCourseTags( ) retourne tous les tags d'un parcours passé en
paramètre. Cette fonction est asynchrone grâce au "async". La structure "try...catch" permet,
14
s'il y a une erreur lancée avec "await", de capturer celle-ci et de renvoyer un message d'erreur
avec un statut 500.
Ensuite, dans le router courses.js, j'ai créé une route, accessible avec la méthode "GET", qui
accède au résultat de la requête effectuée par la fonction getCourseTags( ) :
15
3. Développement de la partie front-end
a. Mise en place de l’environnement de développement
J’ai donc choisi de développer à l’aide du framework Expo, qui apporte des outils qui
facilitent le développement en React Native.
Expo étant déjà installé sur mon ordinateur, j'ai initialisé le projet grâce à la commande expo
init [nom_du_projet]. Les dossiers propres à Expo sont créés, le dossier node_modules qui
comprend toutes les librairies nécessaires au fonctionnement du projet, le fichier App.js qui
sera le point d'entrée de l'application, ainsi que les fichiers app.json, babel.config.js, package-
lock.json et package.json qui sont différents fichiers de configuration.
Une fois le projet initialisé, j'ai pu commencer le développement.
16
Arborescence de la navigation au sein de l’application
Ainsi, tous mes screens seront déclarés à l'intérieur du composant <Stack.Navigator>, grâce
à un composant <Stack.Screen> qui possède 2 propriétés
"name" qui correspond au nom de la route
"component" qui correspond au composant à charger
17
Extrait du composant <NavBar> qui gère l’affichage de la barre de navigation
c. Les fonts
Grâce à Expo, il est possible d'utiliser les polices de Google Font très facilement en installant
la police choisie, par exemple "Montserrat" que j'utilise au sein du projet :
expo install expo-font @expo-google-fonts/montserrat.
Puis dans le fichier App.jsx, j'importe les polices dont j'ai besoin
depuis le dossier '@expo google-fonts/montserrat'. Enfin,
j'utilise le hook "useFonts( )" pour charger les polices au
lancement de l'application. Désormais, j'ai accès à ces polices
depuis n'importe quel fichier de mon projet.
18
d. Les contextes
J’ai utilisé les contextes qui me permettent de faire passer des données à travers
l’arborescence sans avoir à les passer manuellement de composant en composant. Je peux
donc accéder aux variables d’un contexte depuis n’importe où dans l’application. Ainsi
lorsqu’une variable d’un contexte est modifiée, tous les composants qui en dépendent se
mettent à jour.
La géolocalisation :
A son arrivée dans l'application, l'utilisateur est géolocalisé afin d'afficher sa position sur la
carte et d'adapter l'affichage en fonction du lieu où il se trouve. Pour lui demander
l'autorisation et récupérer sa position, j'ai mis un place un contexte React. Dans un nouveau
fichier GeolocationContext.jsx, je crée le contexte GeolocalisationContext grâce à la méthode
createContext( ). Ensuite, je développe le contenu du composant <Geolocation.Provider> de
ce contexte :
J'utilise le hook d'effet "useEffect( )" avec un tableau de dépendance vide, afin
d'exécuter le code à l'intérieur uniquement lorsque le contexte est appelé la
première fois. A l'intérieur du useState( ), je demande l'autorisation à l'utilisateur
grâce à la méthode Location.requestPermissionsAsync( ), puis récupère la position
de l'utilisateur grâce à la méthode Location.getCurrentPositionAsync(). A l'aide du
hook useState( ), je viens stocker la latitude et la longitude dans la variable "location"
.
Dans le return, je peux assigner au provider la valeur de la variable "location" grâce à
la propriété "value". Ainsi, dans mon fichier App.jsx, je peux englober l'intégralité de
mon <NavigationContainer> dans le composant <GeolocationProvider>. Je peux
alors utiliser les variables contenues dans ce provider dans n'importe quel
composant se trouvant en dessous de lui dans l'arborescence de la navigation, et ce,
à l'aide du hook useContext : const {location} = useContext(GeolocationContext);
L’utilisateur :
J'ai également créé un contexte pour stocker l'utilisateur qui est connecté. Dans le
composant <UserProvider>, j'utilise également un useEffect() qui appelle la fonction getUser.
Cette fonction récupère les informations de l'utilisateur enregistré (donc s'il y a un token
enregistré). La requête effectuée à l'API contient le token dans le header, car j'ai fait en sorte
que cette route soit protégée par le middleware lors du développement de l'API.
Cette fois-ci, le tableau de dépendance contient la variable "token", afin que la fonction
getUser() soit exécutée lorsque le contexte est chargé la première fois et à chaque fois que la
variable "token" change.
19
Dans le return de mon provider, je peux assigner la valeur de la variable "values" grâce à la
propriété "value". Ainsi, dans mon fichier App.jsx, je peux englober l'intégralité de mon
<NavigationContainer> dans le composant <UserProvider>.
Je peux alors utiliser les variables user, token et les méthodes qui permettent de les modifier,
dans n'importe quel composant dans l'arborescence, toujours à l'aide du hook useContext() :
const { user } = useContext(UserContext), et ainsi accéder par exemple au nom de l'utilisateur
avec : "user.usr_name". L'affichage au sein de l'application est entièrement dynamique car il
s'adapte aux données de chaque utilisateur.
UserContext.js
e. Écrans développés
Voici le détail que quelques écrans que j’ai pu développer jusqu’à présent. Les
captures d’écran sont disponibles en annexe.
OnBoarding
Lorsque l’utilisateur arrive dans l’application, il arrive sur un écran d’accueil qui lui
explique le principe de l’application, à l’aide d’un carrousel. Une fois à la fin du
carrousel, lorsque l’utilisateur scrolle à nouveau, il arrive sur l’écran de login.
J’ai développé le carrousel en utilisant le composant React Native <ScrollView> qui
permet d’afficher des éléments d’une liste sous la forme d’une liste scrollable.
20
J’ai rencontré une difficulté dans le développement de cet écran. En effet, lorsqu’on
est sur le dernier élément du carrousel et que l’on scrolle à nouveau, on est dirigé vers
le prochain écran.
Cependant, la propriété "onScroll" du composant <ScrollView> ne peut pas intervenir
parce qu'il n'y a pas véritablement de scroll au niveau de la liste.
J'ai donc utilisé la libraire react-native-gesture-handler qui permet de capturer les
gestes de l'utilisateur sur l'écran, et plus particulièrement le composant
<PanGestureHandler>. J'ai également utilisé une fonction trouvée sur le forum
« StackOverFlow », qui me permet de savoir si l'élément affiché à l'écran est le dernier
de la liste.
Login
L'écran "Choose Login" permet à l'utilisateur de choisir de se connecter, de s'inscrire
ou continuer sans être authentifié.
Inscription
J'ai utilisé les librairies Formik et Yup pour la création du formulaire et
la validation des données saisies par l'utilisateur. J'ai développé mon
formulaire d'inscription au sein d'un composant <Formik>. Ce
composant comporte plusieurs propriétés :
initialValues, qui est un objet qui contient le nom de chaque
champ ainsi que leur valeur initiale.
onSubmit, qui contient le code à exécuter lorsque l'utilisateur
soumet le formulaire.
validationSchema, qui contient un objet yup, qui indique les
différents champs, leur type, s'ils sont requis, leur valeur
minimale etc., ainsi que les messages d'erreur à afficher pour
chaque champ. Je peux ainsi procéder à une première
validation des données côté client.
21
Lorsque l'utilisateur soumet le formulaire et qu'il n'y a pas d'erreur côté
client, j'effectue une requête POST auprès de l'API pour enregistrer les
données, grâce à axios.
Si elle renvoie un message d'erreur, par exemple parce que l'adresse
email existe déjà en base de données, je récupère ce message, le stocke
dans la variable "errorMessage" et l'affichage en dessous de mon
formulaire. L'utilisateur est alors informé de l'échec de son inscription
et sait quel champ il doit modifier.
Connexion
Le formulaire de connexion fonctionne de la même manière que le
formulaire d'inscription. J'effectue une première vérification des
données côté client grâce au schéma et au yup.object qui contient mes
vérifications.
Lorsque l'utilisateur soumet le formulaire et qu'il n'y a pas d'erreur côté
client, j'effectue une requête de type POST auprès de l'API pour vérifier
l'identité de l'utilisateur. Si les informations ne sont pas valides, je
récupère le message d'erreur renvoyé par l'API afin de l'afficher à
l'utilisateur. Si l'authentification réussit, je récupère le token qu'elle me
renvoie, le stocke et dirige l'utilisateur au sein de l'application.
22
emprunter pour passer par tous les points d'intérêts. Je stocke donc cette
ligne encodée en base de données, et je la décode en back grâce à la librairie
@mapbox/polylines avant de retourner le résultat de la requête. Une fois la
liste obtenue, j'utilise le composant <Polyline> qui prend en paramètre mon
tableau de coordonnées, et qui dessine la route entre chaque point d'intérêt.
- <ButtonsMap> qui affiche le bouton filtre et le bouton pour lancer un
parcours guidé
- <ParcoursList> qui gère l'affichage d'une liste scrollable grâce au composant
<FlatList>. Pour cela, je récupère tous les parcours en base de données que je
stocke dans un tableau, puis je parcours le tableau à l'aide de la méthode
map( ). Ainsi, pour chaque item, je retourne un <Parcours> qui est un
composant externe, à qui je transmets l'id du parcours qu'il rend.
Ici, il doit couvrir 80% de la largeur de l'écran et resté à l'écran au moins 400ms.
Lorsque c'est le cas, j'appelle la fonction définie au sein de la propriété
onViewableItemsChanged, qui assigne l'id de la course affichée à la variable
« courseDisplay ».
Profil utilisateur
La page Profil de l'utilisateur récupère le contexte UserContext afin de récupérer les
informations de l'utilisateur, y compris son token de session
23
Ce dernier est utilisé lors de la requête POST qui permet la déconnexion de
l'utilisateur. Dans ce cas, il est renvoyé à la page de connexion et la navigation est
réinitialisée grâce au navigation.reset( ).
L’utilisateur a besoin d’être connecté pour avoir pleinement accès à certaines fonctionnalités.
Il fallait donc constituer une passerelle entre l’API et le front pour authentifier l’utilisateur,
avec une attention toute particulière sur la sécurisation du processus.
Les jetons JWT, de par leurs signatures construites grâce à une clé privée détenue par le
serveur, semble être une solution tout indiquée.
Plus de détails à ce sujet seront présents dans ma veille anglophone, disponible en page 28.
Tout d'abord, j'ai installé la librairie "jsonwebtoken" avec la commande npm install
jsonwebtoken. Elle permet de générer et de décoder des tokens lors du processus
d'authentification dans le cadre du protocole OAuth2.
Dans le modèle User, j'ai créé une fonction asynchrone qui permet d'attribuer un token à un
utilisateur grâce à la méthode jwt.sign( ) qui prend en paramètres l'id de l'utilisateur, la clé
secrète qui sera nécessaire au décodage, et le délai d'expiration du token. Ensuite, j’effectue
une requête à la base de données pour ajouter le token dans la table "user".
Pour des raisons de sécurité, il est nécessaire que le mot de passe des utilisateurs ne soit
pas stocké en clair dans la base de données. J'ai donc installé et utilisé la librairie
"objection-password" qui permet automatiquement de générer un hash du mot de passe
avant de le stocker lorsqu'il concerne un champ d'un modèle Objection.
24
Elle effectue une requête en base de données afin de vérifier si l'email ou le nom
d'utilisateur existent déjà. Si c'est le cas, elle renvoie un message que je peux
récupérer côté front. Sinon, elle insère les données dans la base de données (dont le
hash du mot de passe), génère un token grâce à la fonction generateAuthToken( ), qui
est donc stocké, et retourne ce nouvel utilisateur. Afin que la réponse envoyée ne
contienne ni le mot de passe ni le token, j'ai ajouté la fonction suivante au modèle
User :
Update : mise à jour des informations d'un utilisateur avec la méthode PATCH.
Les données que l'utilisateur souhaite modifier sont contenues dans le req.body sous
la forme d'un objet contenant un ensemble de couples clé-valeur. Je récupère les clés
grâce à la méthode Object.keys( ) puis les compare avec les noms des champs qu'il
est possible de modifier. Si l'utilisateur est autorisé à effectuer ces modifications, je
vérifie qu'il existe bien en base de données, puis applique les changements et
retourne les informations de l'utilisateur.
25
Je vérifie que le token envoyé avec la requête correspond à celui stocké en base de
données. Si c'est le cas, j'efface le token stocké, puis renvoie le message "User
disconnected".
Une fois cela fait, j'ai créé un nouveau dossier "middleware", dans lequel j'ai créé le fichier
« auth.js » qui contient la fonction auth( ) qui permet de vérifier l'authentification de
l'utilisateur lors de chaque appel à l'API.
En effet, lors de chaque appel, le token est envoyé dans le header de la requête. Une fois
récupéré, il est décodé grâce à la méthode jwt.verify( ) qui prend en paramètre le token ainsi
que la clé utilisée pour l'encoder. Je récupère ainsi un id d'utilisateur, et j'effectue une
requête à la base de données afin de vérifier qu'un tel utilisateur existe et que le token
correspond bien à celui envoyé. Si c'est le cas, j'autorise l'appel à l'API grâce à la méthode
next( ), sinon un message d'erreur est envoyé : "Please authenticate".
Je peux désormais restreindre l'accès à certaines routes de l'API en ajoutant le middleware
"auth" : par exemple :
26
J'ai créé ensuite une collection, appelée « Skimtrack-API », en précisant dans l'onglet
"Authorization" qu'il s'agit d'un type "Bearer Token" et que le Token est égal à la variable
{{authToken}}.
J’ai créé ensuite la plupart de mes requêtes API, notamment celles qui concernent l'utilisateur.
Je sais qu’un utilisateur reçoit un token lorsqu'il s'inscrit ou se connecte (requêtes "Create
User" et "Login User" dans Postman). Dans l'onglet "Tests" de ces requêtes, j'ai ajouté du
code JavaScript qui me permet d'update la variable "authToken" avec le token renvoyé par
l'API si la réponse possède un statut 200). Ainsi, il est possible de tester l'intégralité des URL
de l'API, afin de détecter une possible erreur dans la gestion de l'authentification des
utilisateurs.
27
2. Recherches anglophones sur le JWT
Ayant très peu abordé la notion d'authentification et de sécurité d'une API lors de la
formation, je me suis documentée sur le principe du JSON Web Token (ou JWT). Voici un
extrait du site officiel jwt.io, ainsi que la traduction.
“In its compact form, JSON Web Tokens consist of three parts separated by dots (.), which
are:
o Header : The header typically consists of two parts: the type of the token, which is JWT,
and the signing algorithm being used, such as HMAC SHA256 or RSA.
o Payload : The second part of the token is the payload, which contains the claims.
Claims are statements about an entity (typically, the user) and additional data. There
are three types of claims: registered, public, and private claims. Do note that for signed
tokens this information, though protected against tampering, is readable by anyone.
Do not put secret information in the payload or header elements of a JWT unless it is
encrypted.
o Signature : To create the signature part you have to take the encoded header, the
encoded payload, a secret, the algorithm specified in the header, and sign that. The
signature is used to verify the message wasn't changed along the way, and, in the case
of tokens signed with a private key, it can also verify that the sender of the JWT is who
it says it is.”
« Dans sa forme compacte, le JSON Web Token est composé de 3 parties séparées par un
point, qui sont :
o le header : Constitué de 2 parties ; le type du token, qui est JWT, et l'algorithme utilisé
pour l'encoder, tel que HMAC SHA256 ou RSA.
o le payload : Il contient des informations à propos d'une entité (qui est généralement
un utilisateur), et des données supplémentaires. Il y a 3 types d'informations : les
informations enregistrées, les informations publiques et les informations privées.
Notez que pour les tokens signés, ces informations sont accessibles par n'importe qui,
même si elles sont protégées contre la falsification. Ne stockez jamais d'informations
secrètes dans le payload ou le header, à moins qu'elles soient encryptées.
o La signature : Pour créer la signature, il faut prendre le header et le payload encodés,
un secret, l'algorithme spécifié dans le header et les signer. La signature est utilisée
pour vérifier que le message n'a pas été changé entre temps, et dans le cas des
tokens signés avec une clé privée, elle permet de vérifier que l'expéditeur du JWT est
bien celui qu'il prétend être. »
28
Conclusion
Concernant le projet, les fonctionnalités de base sont développées. Je suis à la
moitié de mon stage, il me reste encore 3 mois pour continuer le développement
afin de proposer une première version dont le déploiement est prévu au printemps
2021.
En acceptant ce stage, je savais qu'il serait un défi pour moi. Nous avions abordé
les technologies comme React Native et Node.js lors de la formation, mais mes
connaissances ne me permettaient pas à elles-seules de procéder au
développement d'une application mobile assez facilement.
En effet, le développement est un défi de tous les jours, car il me faut apprendre à
l'aide de la documentation officielle, à l'aide des forums dédiés, de tutoriels vidéo,
et reproduire ce que je viens d'apprendre sur mon projet. Je pense que c'est la
meilleure méthode de travail afin de progresser rapidement, et que c'est une
bonne façon d'entrevoir ce qu'est le métier de développeur.
29
Annexes
Annexe 1 – Écran d’onBoarding Annexe 2 – Écran d’inscription
30
Annexe 5 – Écran des parcours Annexe 6 – Écran d’un parcours
31