web-dev-qa-db-fra.com

Implémentation d'une authentification d'API RESTful à l'aide de jetons (Yii/Yii2)

Je construis une API dans Yii 1.x qui sera utilisée avec une application mobile. Une partie du processus implique une connexion (avec un nom d'utilisateur et un mot de passe) à l'aide de la requête JSON suivante ci-dessous: -

// Demande envoyée avec nom d'utilisateur et mot de passe

{
"request" : {
    "model" : {
        "username" : "bobbysmith",
        "password" : "mystrongpassword"
    }
  }
}

// Si connecté avec succès, retourne la réponse suivante

{
"response": {
    "code": 200,
    "message": "OK",
    "model": {
        "timestamp": 1408109484,
        "token": "633uq4t0qdtd1mdllnv2h1vs32"
    }
 }
}

Ce jeton est très important - une fois qu'un utilisateur est connecté à l'application, je souhaite qu'il ait accès à d'autres pages qui le nécessitent. Je souhaite que l'application mobile enregistre ce jeton et si le même 633uq4t0qdtd1mdllnv2h1vs32 Le jeton est trouvé dans toutes les demandes ultérieures, il l'acceptera comme une demande authentifiée (pour cet utilisateur 'bobbysmith').

Je ne sais pas trop comment y parvenir. J'ai fait des recherches et je peux dire que oAuth a été mentionné à quelques reprises, de même que l'authentification de base via HTTPS.

Donc en un mot cette ...

  1. Sur la page d'accueil de l'application mobile, l'utilisateur se connecte correctement avec son nom d'utilisateur et son mot de passe, ce qui envoie une demande à l'API.
  2. Cela renvoie une réponse réussie (illustrée ci-dessus) avec l'horodatage actuel et le jeton tout important.
  3. Le même utilisateur accède à une autre page/vue d'application où ce jeton est a) requis et b) s'il correspond, cela authentifie cet utilisateur (par exemple pour qu'il puisse modifier ce compte, etc.).
  4. Une fois que l'utilisateur a cliqué sur 'Déconnexion', ce jeton est ensuite supprimé (et peut accéder plus longtemps à Mon compte, etc.) - essentiellement un système d'authentification basé sur un jeton.

Quelqu'un peut-il éventuellement expliquer le meilleur moyen d'y parvenir? S'il vous plaît laissez-moi savoir si ce que j'ai dit n'est pas clair à 100% et je fournirai plus d'informations.

Bien que j'utilise PHP, une solution Yii 1.x est idéale car c'est ce que l'API actuelle est construite.

En un mot, l'application garantit que chaque demande adressée au serveur inclut un jeton dans la charge utile ou l'en-tête afin que ce jeton puisse être récupéré sur chaque message suivant, une fois déconnecté, ce jeton est simplement supprimé OR défini sur null /vide

21
Zabs

Informations sur la gestion des interfaces de sécurité

Concentrez-vous sur une solution fournissant à la fois toutes les bonnes choses relatives aux autorisations (RESTful), qui seront probablement:

  • SSL (le plus IMPORTANT, sinon "HTTP-Auth" serait moins important, tout le monde serait en mesure de lire votre en-tête/corps attaque de type homme/au milieu )
  • oAuth (ou mieux oAuth2!)
  • HTTP-Auth
  • Tokens (y compris une durée de vie limitée, actualisez et éventuellement inclure une logique de vérification IP/DeviceUID-> si elle est mobile!)
  • Mots de passe générés par le sel
  • En-têtes HTTP personnalisés pour les ID/ENV/CLIENT vérifications ou quoi que ce soit.
  • Données de corps chiffrées pour Requête et Réponse pour empêcher les manipulations de données

Astuce: Les données personnelles de l'utilisateur devraient toujours être cryptées!


Peut-être une solution

Ci-dessus, vous pouvez voir les informations standard sur les interfaces de sécurité. Pour assurer une sécurité durable, vous pouvez essayer comme dans la partie suivante. Je ne suis pas sûr de votre AppSidePersitence. Peut-être sa sqlLite ou quelque chose comme ça. C'est pourquoi je n'indique pas de schéma de base de données basé sur du code, comme je l'avais fait pour Yii. Vous aurez besoin d'un stockage/persistance dans votre application Yii (backend) et également dans votre application (client) pour stocker les temps et les jetons.

Votre YiiDBModel

enter image description here

-- -----------------------------------------------------
-- Table `mydb`.`user`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`user` (
  `id` INT NOT NULL,
  `username` VARCHAR(255) NOT NULL,
  `password` VARCHAR(255) NOT NULL,
  `lastLogin` DATETIME NULL,
  `modified` DATETIME NULL,
  `created` DATETIME NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB;

----------------------------------------------------
-- Table `mydb`.`authToken`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`authToken` (
  `id` INT NOT NULL,
  `userId` INT NOT NULL,
  `token` VARCHAR(255) NOT NULL,
  `created` DATETIME NOT NULL,
  PRIMARY KEY (`id`, `userId`),
  INDEX `fk_authToken_user_idx` (`userId` ASC),
  UNIQUE INDEX `token_UNIQUE` (`token` ASC),
  CONSTRAINT `fk_authToken_user`
    FOREIGN KEY (`userId`)
    REFERENCES `mydb`.`user` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

Votre modèle AppPersitence

enter image description here

Gérer correctement votre jeton et assurer la sécurité de la connexion

  1. Tout jeton que vous générez du côté de Yii-Application sera stocké avec une date-heure "créée" dans votre base de données YiiApp (voir le tableau authToken). Chaque utilisateur a un seul "jeton", qui sera généré après une demande de "connexion" correcte. De cette façon, vous n'avez pas besoin de vérifier les jetons lorsque vous vous "connectez". Défini par le schéma, "token" est unique! Je pense qu'il n'est pas nécessaire de gérer les données historiques (anciens jetons expirés).
  2. Une fois que la connexion de l'utilisateur a été validée "succès" par Yii, vous générez un nouveau jeton d'utilisateur avec l'horodatage actuel, qui sera stocké dans votre base de données YiiApp. Dans votre YiiApp, vous devez configurer un "délai d'expiration", qui sera ajouté à l'horodatage actuel, par exemple, si vous souhaitez utiliser "horodatage": l'horodatage actuel est: 1408109484 et votre délai d'expiration est défini sur 3600 (qui est 3600 sec = 1h). Donc ... votre date d'expiration qui sera envoyée via l'API est (1408109484+3600). Btw. Astuce: Vous n'avez pas besoin d'envoyer des attributs tels que "code": 200. Les codes de réponse sont inclus dans vos données d'en-tête Requests/Response. 

    ** 200 OK Response-Example, après la connexion de l'utilisateur, contient la date "expirée" calculée: ** 

     {
        "error": null,
        "content": {
            "expires": 1408109484,
            "token": "633uq4t0qdtd1mdllnv2h1vs32"
        }
    }
    
  3. Important: Toutes les demandes que vous souhaitez sécuriser doivent être envoyées avec votre "jeton" généré. Ce qui sera probablement stocké dans votre deviceStorage. Vous pouvez gérer vos "états de connexion" - vraiment RESTful si vous utilisez HTTP-Response-Codes right, par exemple, 200 OK (si tout va bien) ou 401 (non autorisé, l'utilisateur n'est pas connecté ou en session. est expiré). Vous devez valider votre demande d'utilisateur côté Yii. Lire le jeton à partir des demandes entrantes, le valider en raison des jetons donnés dans la base de données et comparer la BD "créée" avec l'heure actuelle de la demande (requêtes HTTP). 

    ** Exemple de demande, schéma par défaut pour toute demande de sécurité: ** 

    {
        "token": "633uq4t0qdtd1mdllnv2h1vs32"
        "content": {
            "someDataYouNeed" : null
        }
    }
    

    ** 401 Exemple de réponse non autorisée, jeton expiré: ** 

    {
        "error": 1, // errorCode 1: token is expired
        "content": {
            "someDataYouNeed" : null
        }
    }
    

    ** 401 Réponse non autorisée-Exemple, l'utilisateur n'est pas connecté (aucun jeton n'existe dans YiiDB): ** 

    {
        "error": 2, // errorCode 2: user is not logged in
        "content": {
            "someDataYouNeed" : null
        }
    }
    
  4. Maintenir une session utilisateur active? C'est assez facile. Il suffit de mettre à jour "créé" -date dans authToken- Table à l'heure actuelle de la demande. Faites-le à chaque fois, une demande valide a été envoyée par l'utilisateur. De cette façon, la session n'expirera pas si l'utilisateur est toujours actif. Assurez-vous que votre jeton de base de données n’a pas expiré avant de mettre à jour le champ expires- Date dans la base de données. Si aucune demande n'est envoyée pendant l'expiration de la session, le maintien en vie ne sera plus possible. 

    Désolé, mais ajouter des codes PHP serait trop. 

55
lin

Si vous construisez pour une application mobile native, il serait judicieux de vous fier à la sécurité de la mémoire native (par exemple, le trousseau iOS) et non à une solution basée sur les cookies. Sinon, comment vous avez décrit semble bien. Tant que votre charge utile est envoyée via SSL, peu importe que le jeton soit dans le PUT ou dans le POST. La gestion de vos jetons (c'est-à-dire les délais d'expiration) sont des décisions que vous devez prendre. Back-end Je ferais ce que vous décrivez en maintenant le jeton dans votre base de données, puis supprimez-le lorsqu'il est devenu obsolète et renvoyez un message à votre application client pour le remettre en mode déconnecté/demander des informations d'identification. 

EDIT: Découvrez cet impressionnant tut du prolifique Phil Sturgeon. Il possède également une excellente bibliothèque CI pour la construction d'API RESTful dans CI, qui mérite peut-être d'être étudié.

http://philsturgeon.uk/blog/2013/07/building-a-decent-api

http://code.tutsplus.com/tutorials/working-with-restful-services-in-codeigniter--net-8814

0
Mike Miller

À ce stade, vous êtes probablement passé à Yii2 et la solution la plus propre consiste à utiliser les classes incluses pour les API RESTful, ou de les implémenter dans n’importe quel framework.

Source: HttpBearerAuth.php

Les avantages sont expliqués en détail dans cet article , mais pour résumer, il est préférable d’utiliser votre solution avec en-tête de requête, car les paramètres GET peuvent être sauvegardés dans des journaux et le mot de passe de utilisez pas SSL (vous devriez!)

0
Razvan Grigore