Featherjs – Authentification avec token


Dans l’article précédent: introduction à feathersjs , nous avons abordé :

  • La création d’une api Restful avec featherjs en utilisant Sequelize . On a choisi MySQL comme gestionnaire de base de données.
  • Des exemples d’utilisation de service feathers tels que : « create, update, delete, get« ..
  • Des requêtes complexes sans toucher au code
  • Le tri, le nombre de lignes à récupérer..

Dans cet article, nous présenterons l’authentification d’un utilisateur.

Authentification

Il s’agit de permettre à un utilisateur de s’authentifier grâce à la saisie d’un couple « identifiant/mot de passe ». En étant connecté, il pourra y accéder aux pages accessibles uniquement aux utilisateurs authentifiés.

Nous allons partir sur le même principe que l'authentification avec expressjs .

Comme pour la création d’un type service avec feathers, il est possible de créer un type authentication . Voici la commande

feathers generate authentication

La console nous demande :

  • le nom du service qu’on souhaite avoir – on saisit : fos_users
  • le choix type de service – on choisit sequelize
  • le choix du gestionnaire de base de données – on indique MySQL (MariaDB)

Modification du modèle

Modifions le modèle featherjs/src/models/fos_users.model.js. Nous allons ajouter les champs décrits dans notre table fos_user

const fosUsers = sequelizeClient.define('fos_users', {

    id: {
      type: DataTypes.INTEGER(11),
      allowNull: false,
      primaryKey: true,
      autoIncrement: true
    },
    username: {
      type: DataTypes.STRING(180),
      allowNull: false
    },
    username_canonical: {
      type: DataTypes.STRING(180),
      allowNull: false,
      unique: true
    },
    email: {
      type: DataTypes.STRING(180),
      allowNull: false
    },
    email_canonical: {
      type: DataTypes.STRING(180),
      allowNull: false,
      unique: true
    },
    enabled: {
      type: DataTypes.INTEGER(1),
      allowNull: false
    },
    salt: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    password: {
      type: DataTypes.STRING(255),
      allowNull: false
    },
    last_login: {
      type: DataTypes.DATE,
      allowNull: true
    },
    confirmation_token: {
      type: DataTypes.STRING(180),
      allowNull: true,
      unique: true
    },
    password_requested_at: {
      type: DataTypes.DATE,
      allowNull: true
    },
    roles: {
      type: DataTypes.TEXT,
      allowNull: false
    },
    facebook_id: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    facebook_access_token: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    google_id: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    google_access_token: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    twitterid: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    twitter_token: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    nickname: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    first_name: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    last_name: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    profile_picture: {
      type: DataTypes.TEXT,
      allowNull: true
    },
    email_rs: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    infos: {
      type: DataTypes.TEXT,
      allowNull: true
    },
    country_isoCode: {
      type: DataTypes.STRING(10),
      allowNull: true
    },
    country_name: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    city_name: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    location_timeZone: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    browser_ua_name: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    browser_ua_ver: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    browser_ua_family: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    browser_ua_company: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    browser_ua_engine: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    browser_os_name: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    browser_os_family: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    browser_device_name: {
      type: DataTypes.STRING(255),
      allowNull: true
    },
    created_at: {
      type: DataTypes.DATE,
      allowNull: true
    },
    updated_at: {
      type: DataTypes.DATE,
      allowNull: true
    }

  },{
    tableName: 'fos_user',
    underscored: false,
    timestamps: false
  }, {
    hooks: {
      beforeCount(options) {
        options.raw = true;
      }
    }
  });

Création d’un utilisateur

On crée un utilisateur dans notre table avec les informations suivantes :

  • username: miary
  • password: test

On peut créer cet utilisateur en utilisant POSTMAN :

  • Méthode : POST
  • URL : http://localhost:3030/fos_users
  • Dans Body > x-wwww-form-urlencoded , on enregistre les champs comme sur cette image:
  • On clique sur le bouton « SEND« 

Les champs supplémentaires tels que : (username_canonical, email_canonical, enabled, roles) sont des champs obligatoires (de type NOT NULL)

Notre utilisateur a bien été créé comme on peut le voir sur l’image suivante.

Il lui a été attribué l’identifiant "id": 590. Si on visualise la table, on a :

Connexion avec cet utilisateur

On modifie featherjs/config/default.json pour spécifier que nous allons utiliser le champ username pour l’identifiant

"local": {
      "entity": "user",
      "usernameField": "\username",
      "passwordField": "password"
}

Retournons dans POSTMAN :

Et voilà, on obtient un joli token comme sur cette image :

Que veut dire ce token? . Pour le décoder, allons copier le code et allons sur ce lien https://jwt.io/ . Collons ensuite le code accessToken dans le champ de gauche. On obtient 3 blocs dans la colonne de droite.

Protection d’une URL

Nous allons protéger une nouvelle URL : http://localhost:3030/api/event .

Pour cela, nous allons créer un service event

Dans la console, on saisit:

feathers generate service

On remarque une spécificité dans la création de ce service. A la question:

? Does the service require authentication?

On a répondu yes

Une fois le service créé. On ajuste featherjs/src/models/event.model.jspour faire correspondre les champs définis dans le fichier aux aux champs dans notre table.

…Dans POSTMAN :

Et bim !! message d’erreur

{
    "name": "NotAuthenticated",
    "message": "No auth token",
    "code": 401,
    "className": "not-authenticated",
    "data": {},
    "errors": {}
}

En effet, comme on a veut que l’accès à cette ressource soit uniquement réservé aux utilisateurs authentifés.

Pour remédier à celà, il faut ajouter le token dans le Header de l’URL.

  • Dans Authorization > Puis dans TYPE > On choisit: Bearer Token
  • Dans le champ de droite token > On colle le token utilisé plus haut.

  • Et on clique sur le bouton « SEND »

Et cela fonctionne comme par magie