7

Viele Beispiele zu RESTful-Webdiensten berücksichtigen nicht das Problem, dass viele Anwendungen heute Multi-User sind.Was ist die richtige Methode zum Autorisieren und Strukturieren eines RESTful-Backends?

Stellen Sie sich ein Multi-User Backend vor, das eine RESTful API aussetzt. Die Back-End-Datenarchitektur verwendet eine gemeinsam genutzte Datenbank und ein gemeinsames Schema. Jeder Tisch wird einen Verweis auf ein tenant_id enthalten:

+-------------+----+-----------------+ 
| tenant_name| id | shared_secret | 
+-------------+----+-----------------+ 
|   bob | 1 | 2737sm45sx543 | 
+-------------+----+-----------------+ 
|  alice | 2 | 2190sl39sa8da | 
+-------------+----+-----------------+ 

+-------------+----+-------+-----------+ 
| pet_name | id | type | tenant_id | 
+-------------+----+-------+-----------+ 
|  fuffy | 1 | dog |   1 | 
+-------------+----+-------+-----------+ 
|  kerry | 2 | cat |   2 | 
+-------------+----+-------+-----------+ 

Frage 1: mit drei oder mehr Client-Anwendungen (zB Android, iOS und Web App) mit dem RESTful-Backend der Interaktion, wie würden Sie die Authentifizierung durchführen gegen das Backend?

RESTful backend, API, HTTP-Verbs, shared database and schema 
| 
| 
+---- Web Application (Client 1) 
|  | 
|  + Alice 
|  | 
|  + Bob 
| 
+---- Android Application (Client 2) 
|  | 
|  + Alice 
|  | 
|  + Bob 
| 
+---- iOS Application (Client 3) 
|  | 
|  + Alice 
|  | 
|  + Bob 
| 

Jeder Client sollte Alice und Bob erlauben, ihre Haustiere zu verwalten. Jeder Client ist eine GUI und wird das Backend verwenden (intern, um HTTP-Anfragen zu stellen). Frage: Wie kann sich jeder Kunde gegen das Backend authentifizieren?

Angenommen, HMAC (es ist perfekt RESTful, keine Sitzungen): Diese Methode beinhaltet Signieren der Nutzlast mit einem gemeinsamen Geheimnis (nie über die Leitung gesendet). Sollte jeder Kunde eine eigene Kopie der Tabelle tenant haben (die das Feld shared_secret enthält)?

Android App -> Client Sign -> Signed Request -> Backend -> Result 
    Web App -> Client Sign -> Signed Request -> Backend -> Result 

Frage 2: Was sollte den Blick der Ressource-URI wie?

Hier sind zwei Möglichkeiten für die Möglichkeiten, Bob Haustiere zu bekommen:

Möglichkeit # 1: Die Authorization Header geben Ihnen den Mieter (unique) Namen:

GET /pets HTTP/1.1 
Host: www.example.org 
Authorization: bob:c29kYW9kYSBhb2lzYWRoIGYgZDUzNDUz 

Möglichkeit # 2.

GET /pets/tenant_id=1 HTTP/1.1 
Host: www.example.org 
Authorization: bob:c29kYW9kYSBhb2lzYWRoIGYgZDUzNDUz 
+0

Seien Sie vorsichtig bei der Verwendung des Ausdrucks Multi-Tenant. Ich bin nicht überzeugt, dass es bedeutet, was Sie denken, dass es tut. Sehen Sie Details hier http://msdn.microsoft.com/en-us/library/aa479086.aspx –

+0

@Gaz_Edge bedeutet es virtuelle Partition Daten zwischen den Clients und eine einzige Instanz wird mehr Kunden dienen, das ist, was ich tue. Sind Sie einverstanden? – gremo

+1

Ich denke, dass Sie dies zu kompliziert machen. Sie haben 1 Web Service, n Web Service Clients und x Benutzer ja? –

Antwort

4

Teil 1

(Denken laut:? Haben Sie bereits HTTP und HMAC verwenden entschieden Wenn ja, warum Sie fragen uns)

Ich würde vorschlagen, HTTPS mit Grund Auth. Einfach. Es ist immerhin gut genug für Stripe.

Referenzen:

aktualisieren: Hier ist einige zusätzliche Details darüber, wie die Auth zu handhaben:

  1. Jede Client-Anwendung den Dienst kontaktieren Sie einen API-Schlüssel verwenden. Mit HTTPS und Basic Auth stellt der Client seinen API-Schlüssel als Basisauthentifizierungs-Benutzernamen zur Verfügung. Es muss kein Passwort angegeben werden, da es HTTPS verwendet. Sie müssen jeder Anwendung einen API-Schlüssel zuweisen (Web-App, Android, iOS). Ich sehe zwei Möglichkeiten:

    A. Eine Option besteht darin, jedem Benutzer einen API-Schlüssel zu geben, der für alle Clients freigegeben ist.

    B. Eine andere Möglichkeit ist es, jedem Client eine einzigartige Anwendung zu geben.)

  2. Aber wie bekommt man die Schlüssel zu den Kunden in erster Linie? Erstellen Sie einen API-Endpunkt für die Schlüsselanforderung. Ich würde vorschlagen, jedem Kunden einen "Starter" -Schlüssel zu geben, der nur verwendet wird, um diesen Endpunkt zu kontaktieren. (Der Startschlüssel gewährt keinen anderen Zugriff.) Wenn ein Benutzer den Client zum ersten Mal verwendet, muss er sich authentifizieren. Der Client leitet dies an den Endpunkt "Schlüsselanforderung" weiter, damit er einen dem Benutzer zugeordneten Schlüssel generieren kann. Von diesem Zeitpunkt an hat jeder Client einen kundengebundenen API-Schlüssel. 2

Teil

Betrachten jeder Mieter eine Sub-Domain zu geben. Wenn Sie Rails (oder wahrscheinlich einen modernen Webstapel) verwenden, können Sie die Subdomäne verwenden, um die Tenant-ID zu suchen. Dann können Sie Ihre API wie folgt verwendet werden:

GET http://tenant1.app.co/pets 
GET http://tenant2.app.co/pets 
GET http://tenant3.app.co/pets 

Referenzen (Rails spezifisch, sondern sollten über Web-Stacks hilfreich sein):

Hinweis: Wie Ihr Beispiel suggeriert, würde ich der Einfachheit halber nicht r e-Verwenden Sie die gleiche Haustier-ID für verschiedene Mieter. Zum Beispiel ist die folgende einfacher Weg zu gehen:

GET http://tenant1.app.co/pets/200 
GET http://tenant2.app.co/pets/201 
GET http://tenant3.app.co/pets/202 

Der Ansatz, den ich beschreiben habe, ist viel sauberer als tenant_id als Abfrage-Parameter übergeben. Außerdem fühlt sich die Verwendung von tenant_id als Parameter falsch an. Ich verwende gerne Parameter für mehr "algorithmische" Dinge, wie ich in "RESTful Web Services" von Ruby und Richardson gelesen habe.

Referenzen:

+0

Ich mag den Teil 2, ich werde für Subdomains gehen. Aber Teil 1 erklärt nicht die Herausforderung, jede Anwendung gegen das Backend zu authentifizieren. Vielleicht ist es mein schlechtes Englisch und ich kann das Problem nicht erklären. Ich habe HMAC gewählt, da zwischen den Anfragen kein Status besteht. Warum schlägst du Basic vor? – gremo

+0

Ich schlug HTTPS + Basic Auth vor, weil es die einfachste Sache ist, die funktioniert. Ich habe Referenzen zur Verfügung gestellt, wenn Sie sich in alle Vor- und Nachteile vertiefen möchten. –

+0

@Gremo, ich habe nur ein paar zusätzliche Details zu Teil 1 (Auth) hinzugefügt. –

3

Mit 'Multi-Tenant' meinen Sie einfach application/Web-Service-Benutzer: Die tenant_id wird als Abfrageparameter gesendet? Multi-Tenant kann oft etwas viel komplizierteres bedeuten msdn.microsoft.com/en-us/library/aa479086.aspx.

Sie müssen jeden Benutzer mit Ihrem Webdienst authentifizieren. Dies kann mit einer einfachen HTTP-Authentifizierung über SSL erfolgen.

Aus Sicht der Web Services würden Sie die Authentifizierung für alle drei Clients durchführen. Der Service interessiert sich nicht für die Art des Kunden - das ist der Punkt. Möglicherweise benötigen Sie für Ihre Kunden unterschiedliche Darstellungen, z. XHTML oder JSON. Ich mag es, die Dinge einfach zu halten und immer JSON zu wählen.

Für die Ressourcen besteht die einfachste Möglichkeit, sie zu verwalten, darin, eine Benutzerressource als oberste Ebene zu haben und dann alle Ressourcen für jeden Benutzer zusammenzufassen, z.

Das Großartige dabei ist, dass Sie Code hinzufügen können, um jede Anfrage zu autorisieren, z. Sie können zwei Benutzer haben, Fred und Jack. Beide Benutzer werden die Authentifizierung weitergeben, aber Sie sollten nur zulassen, dass fred seine Ressourcen anfordert, und jack, um seine anzufordern. Sie müssen nur die Berechtigungsprüfungen in Ihrer API hinzufügen, z. Holen Sie den Benutzernamen von der URI, erhalten Sie den Benutzernamen des authentifizierten Benutzers, überprüfen Sie, dass sie identisch sind.Wenn nicht etwas wie http 403 verboten, wenn sie gleich sind, erlauben Sie die Anfrage.

Ich denke, wenn Sie noch unklar sind, müssen Sie sich über die Details von REST informieren. Bei weitem das beste Buch zum Thema ist dieses RESTful Web Services. Es deckt REST von den ersten Grundsätzen ab. Es hat auch einen sehr schönen Abschnitt zum Entwerfen von Ressourcen und zum Verwalten von Benutzern und mehreren Clients.

+0

Ich werde die Frage bearbeiten, um es klarer zu machen. In der Zwischenzeit: Ich habe nur einen Web Service (das RESTful Backend) und "n" mögliche Clients (Apps) die es verbrauchen. Benutzer (Mieter) verwenden einen der "n" -Clients (vielleicht sogar mehr, d. H. Die Webanwendung und den Android-Client). – gremo

+0

Ich möchte Gaz ein upvote geben, nur damit er/sie keine Punktzahl von 666 hat. –

+0

awww, aber ich mochte es! ;-) –

1

Ich bin mir nicht sicher, die Frage zu verstehen, da die Mandantenfähigkeit in diesem Fall etwas übertrieben erscheint. Allerdings kann ich versuchen, die zweite Frage zu beantworten.

REST ist eine „ressourcenbasierten“ Architektur und Sie müssen erkennen, dass /pets und /pets/?tenant=1 nicht auf die gleiche Ressource bezieht:

  • /pets auf die Haustiere des aktuellen Benutzers bezieht,
  • /pets/?tenant=1 bezieht sich auf Bobs Haustiere.

Während keine Lösung falsch ist, ist es normalerweise besser, die zweite Lösung zu bekommen. URIs sind in der Tat so konzipiert, dass sie geteilt werden, und Sie haben mehr Gründe, "Bobs Haustiere" (auch wenn sie Authentifizierung und Autorisierung benötigen) zu teilen als die Zusammenfassung "meine Haustiere", die für jeden Benutzer anders wäre.

Siehe Should resource ids be present in urls? für eine ähnliche Diskussion ...

1

Wenn HTTP das Protokoll alle 3-Client-Typen verwenden ist, Sie nur ein Authentifizierungsschema benötigen, sollten zu implementieren. Sie können Ihr Gift auswählen - Basic, Digest, Oauth2 oder Cookie sind einige häufig verwendete Methoden. Da es über HTTP ist, sehe ich keinen Grund, diese Logik zu replizieren. Es gibt wahrscheinlich mehrere Frameworks, die dies für Sie abhängig von Ihrer Plattform abstrahieren.

Um den Client-Typ zu unterscheiden, können Sie einen HTTP-Header verwenden. Die user-agent könnte dies bereits ermöglichen. Eine andere Option wäre die Verwendung eines benutzerdefinierten Headers, den Sie definieren. Jeder HTTP-Client kann Header festlegen, und jeder Server kann benutzerdefinierte Header verarbeiten. Ein anständiges Web-Framework wird diese Ihnen relativ leicht zugänglich machen. Als Back-End-Service vermute ich, dass Sie alle Kundenanforderungen einheitlich oder so weit wie möglich bearbeiten möchten. Sicher, Aufrechterhaltung eines Backend ist zu drei vorzuziehen.

So weit wie Ihre API aussehen sollte - es liegt ganz bei Ihnen. Um zu bleiben RESTful, how to GET a cup of coffee ist es wert, die Lektüre - obligatorischen Link zu Roy Fielding's thesis einfügen. Die Chancen sind, was Sie wirklich suchen, ist eine Anleitung zum Schreiben von "findigen" Links.

Von den Optionen, die Sie auflisten, bevorzugen Sie die zweite, /pets?userId=bob, wenn Benutzer möglicherweise auf alle Haustiere im System zugreifen müssen. Bevorzugen Sie die erste, /pets, wenn ein Benutzer immer nur auf ihre Haustiere zugreifen müssen.