it-swarm.com.de

Implementieren einer RESTful-API-Authentifizierung mithilfe von Token (Yii/Yii2)

Ich baue in Yii 1.x eine API, die mit einer mobilen Anwendung verwendet wird. Ein Teil des Prozesses umfasst ein Login (mit einem Benutzernamen und einem Kennwort), wobei die folgende JSON-Anforderung verwendet wird: -

// Anfrage mit Benutzername und Passwort gesendet

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

// Wenn Sie sich erfolgreich angemeldet haben, geben Sie die folgende Antwort zurück

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

Dieses Token ist sehr wichtig - sobald ein Benutzer in der App angemeldet ist, möchte ich, dass er Zugriff auf andere Seiten hat, auf denen er angemeldet sein muss. Ich möchte, dass die mobile App dieses Token speichert und dasselbe 633uq4t0qdtd1mdllnv2h1vs32 Das Token wird in allen nachfolgenden Anforderungen gefunden, es akzeptiert dies als authentifizierte Anforderung (für diesen Benutzer 'bobbysmith').

Ich bin ein bisschen unsicher, wie ich das am besten machen kann, ich habe ein wenig recherchiert und kann oAuth zusammen mit der Basisauthentifizierung über HTTPS mehrmals erwähnt.

Also in aller Kürze das ...

  1. Auf der Startseite der mobilen App meldet sich der Benutzer korrekt mit seinem Benutzernamen und Kennwort an. Dies sendet eine Anforderung an die API.
  2. Dies gibt eine erfolgreiche Antwort (oben gezeigt) mit dem aktuellen Zeitstempel und dem wichtigen Token zurück.
  3. Derselbe Benutzer geht zu einer anderen App-Seite/Ansicht, wo dieses Token a) erforderlich ist und b) wenn er übereinstimmt, wird der Benutzer authentifiziert (z. B. damit er das Konto bearbeiten kann usw.).
  4. Sobald der Benutzer auf "Abmelden" klickt, wird dieses Token entfernt (und kann länger auf Mein Konto usw. zugreifen) - im Wesentlichen ein Token-basiertes Authentifizierungssystem.

Kann jemand möglicherweise den besten Weg erklären, um dies zu erreichen? Bitte lassen Sie mich wissen, wenn das, was ich gesagt habe, nicht zu 100% klar ist und ich Ihnen weitere Informationen geben werde.

Während ich PHP verwende, ist eine Yii 1.x-Lösung ideal, da die aktuelle API dies nutzt.

Kurz gesagt, die App stellt sicher, dass jede Anforderung an den Server ein Token in der Payload oder im Header enthält, sodass dieses Token bei every nachfolgender Post abgerufen werden kann. Nach dem Abmelden wird dieses Token einfach entfernt OR auf null/leer setzen

21
Zabs

Informationen zum Umgang mit Sicherheitsschnittstellen

Konzentrieren Sie sich auf eine Lösung, die alle guten (REST-fähigen) Authentifizierungsmaterialien auf einmal zur Verfügung stellt. Dies wird wahrscheinlich Folgendes sein:

  • SSL (am WICHTIGSTEN, sonst wäre "HTTP-Auth" weniger sinnvoll, jeder kann Ihren Request Header/Body Man-in-the-Middle-Angriff auslesen)
  • oAuth (oder besser oAuth2!)
  • HTTP-Auth
  • Token (einschließlich einer begrenzten Lebensdauer, Aktualisierung und möglicherweise IP/DeviceUID-Prüflogik-> wenn es mobil ist!)
  • Salz generierte Passwörter
  • Benutzerdefinierte HTTP-Header für ID/ENV/CLIENT Überprüfungen oder was auch immer.
  • Verschlüsselte Body-Daten für Request und Response, um Datenmanipulationen zu verhindern

Hinweis: Persönliche Benutzerdaten sollten immer verschlüsselt sein!


Vielleicht eine Lösung

Oben sehen Sie die Standardinformationen zu Sicherheitsschnittstellen. Um dauerhafte Sicherheit zu gewährleisten, können Sie es wie im nächsten Teil versuchen. Ich bin nicht sicher über Ihre AppSidePersitence. Vielleicht ist es sqlLite oder so ähnlich. Deshalb verweise ich auf kein codebasiertes DB-Schema, wie ich es bei Yii gemacht habe. Sie benötigen Speicher/Persistenz in Ihrer Yii-Anwendung (Backend) und auch in Ihrer App (Client), um Zeiten und Token zu speichern.

Ihr 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;

Ihr AppPersitenceModel

enter image description here

Umgang mit Ihrem Token und Gewährleistung der Anmeldesicherheit

  1. Alle Token, die Sie auf der Yii-Application-Seite generieren, werden mit einer "erstellten" -Datetime in Ihrer YiiApp-Datenbank gespeichert (siehe Tabelle authToken). Jeder Benutzer hat nur ein "Token", das nach einer korrekten "Login" -Abfrage generiert wird. Auf diese Weise müssen Sie während des "Anmeldens" keine Token überprüfen. Durch das Schema definiert, ist "Token" einzigartig! Ich denke, es besteht keine Notwendigkeit, historische Daten (alte abgelaufene Token) zu verarbeiten.
  2. Nachdem das Benutzer-Login von Yii als "erfolgreich" bestätigt wurde, generieren Sie ein neues Benutzer-Token mit dem aktuellen Zeitstempel, das in Ihrer YiiApp-DB gespeichert wird. In Ihrer YiiApp müssen Sie eine "Ablaufzeit" konfigurieren, die zum aktuellen Zeitstempel hinzugefügt wird, beispielsweise wenn Sie "Zeitstempel" verwenden möchten: Der aktuelle Zeitstempel lautet: 1408109484 und Ihre Ablaufzeit ist auf 3600 (was ist.) 3600 sec = 1h). Also ... Ihr Ablaufdatum, das per API gesendet wird, lautet (1408109484+3600). Übrigens Hinweis: Sie müssen keine Attribute wie "code": 200 senden. Antwortcodes sind in Ihren Requests/Response-Header-Daten enthalten. 

    ** 200 OK Antwort-Beispiel, nach erfolgreicher Benutzeranmeldung enthält das berechnete "abgelaufene" Datum: ** 

     {
        "error": null,
        "content": {
            "expires": 1408109484,
            "token": "633uq4t0qdtd1mdllnv2h1vs32"
        }
    }
    
  3. Wichtig: Alle Anfragen, die Sie sichern möchten, müssen mit Ihrem generierten User-Token gesendet werden. Welches wird wahrscheinlich in Ihrem DeviceStorage gespeichert. Sie können mit Ihren "Login-Status" - wirklich RESTful - umgehen, wenn Sie HTTP-Response-Codes Right verwenden, z. B. 200 OK (wenn alles in Ordnung ist) oder 401 (nicht berechtigt, Benutzer ist nicht angemeldet oder Sitzung) ist abgelaufen). Sie müssen Ihre Benutzeranfragen auf Yii-Seite überprüfen. Lesen Sie das Token aus eingehenden Anforderungen aus, validieren Sie es aufgrund der angegebenen Token in der Datenbank und vergleichen Sie "erstellte" -DB mit der aktuellen eingehenden Request-Time (HTTP-Requests). 

    ** Request-Example, Standardschema für alle Sicherheitsanforderungen: ** 

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

    ** 401 Unzulässiges Antwort-Beispiel, Token abgelaufen: ** 

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

    ** 401 Unauthorized Response-Beispiel, Benutzer ist nicht angemeldet (in YiiDB ist kein Token vorhanden): ** 

    {
        "error": 2, // errorCode 2: user is not logged in
        "content": {
            "someDataYouNeed" : null
        }
    }
    
  4. Eine User-Session am Leben erhalten? Das ist ziemlich einfach. Aktualisieren Sie einfach "erstellt" -Datum in authToken- Tabelle auf die aktuelle Anforderungszeit. Tun Sie dies jedes Mal, wenn eine gültige Anfrage vom Benutzer gesendet wurde. Auf diese Weise läuft die Sitzung nicht ab, wenn der Benutzer noch aktiv ist. Stellen Sie sicher, dass Ihr DB-Token nicht abgelaufen ist, bevor Sie das expires- Date-Feld in der DB aktualisieren. Wenn während der Sitzung keine Anforderung gesendet wird, ist das Keep-Alive nicht mehr möglich. 

    Sorry, aber das Hinzufügen von PHP-Codes wäre zu viel. 

55
lin

Wenn Sie eine native mobile App erstellen, ist es sinnvoll, sich auf die Sicherheit des nativen Speichers (z. B. des iOS-Schlüsselbundes) zu verlassen und nicht auf eine Cookie-basierte Lösung. Ansonsten scheint es gut zu sein, wie Sie es beschrieben haben. Solange Ihre Payload über SSL gesendet wird, spielt es keine Rolle, ob sich das Token im PUT oder im POST befindet. Ihr Token-Management (dh Ablaufzeiten) sind Geschäftsentscheidungen, die Sie treffen müssen. Backend Ich würde es tun, während Sie das Token in Ihrer Datenbank beschreiben und halten und es löschen, wenn es aus irgendwelchen Gründen nicht mehr funktioniert, und eine Nachricht an Ihre Client-App zurückschicken, um es wieder in den Abmelden-Modus zu bringen und die Anmeldeinformationen erneut anzufordern. 

EDIT: Schauen Sie sich dieses fantastische Tut vom produktiven Phil Sturgeon an. Er hat auch eine großartige CI-Bibliothek zum Erstellen von RESTful-APIs in CI, die sich vielleicht lohnt.

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

Zu diesem Zeitpunkt haben Sie wahrscheinlich zu Yii2 gewechselt, und als zukünftige Referenz wäre es die sauberste Lösung, eingeschlossene Klassen für RESTful-APIs zu verwenden, oder Sie können sie in einem beliebigen Framework implementieren.

Quelle: HttpBearerAuth.php

Die Vorteile werden ausführlich in diesem Artikel erläutert. Zusammenfassend ist es jedoch besser, Ihre Lösung mit request-Kopfzeilen zu verwenden, da GET-Parameter in Protokollen gespeichert werden können und das Basic Auth-Kennwort leicht abgefangen werden kann, wenn Sie dies tun Verwenden Sie kein SSL (sollten Sie!)

0
Razvan Grigore