Ich bin neu in diesem Authentifizierungsbereich. Ich habe viel gesucht, konnte jedoch keine Möglichkeit finden, die REST-Aufrufe des Play-Servers zu authentifizieren. Was sind die verschiedenen Möglichkeiten und Best Practices?Play Framework REST mit Standardauthentifizierung und SSL
Antwort
Ein sehr einfacher Weg ist die Verwendung von Action Composition. Werfen Sie einen Blick auf diesen von Guillaume Bort zur Verfügung gestellten Gist: https://gist.github.com/guillaumebort/2328236. Wenn Sie es in einem Asynchron-Aktion verwenden möchten, können Sie etwas schreiben wie:
def BasicSecured[A](username: String, password: String)(action: Action[A]): Action[A] = Action.async(action.parser) { request =>
request.headers.get("Authorization").flatMap { authorization =>
authorization.split(" ").drop(1).headOption.filter { encoded =>
new String(org.apache.commons.codec.binary.Base64.decodeBase64(encoded.getBytes)).split(":").toList match {
case u :: p :: Nil if u == username && password == p => true
case _ => false
}
}
}.map(_ => action(request)).getOrElse {
Future.successful(Unauthorized.withHeaders("WWW-Authenticate" -> """Basic realm="Secured Area""""))
}
}
SSL nichts mit Standardauthentifizierung zu tun haben. Sie können HTTPS für API entweder direkt oder über einen Front-End-HTTP-Server wie ngnix verwenden. Es gibt ziemlich gute Details in der Play-Dokumentation zu diesem Thema.
Lesen Sie die folgende Readme/Artikel: Securing Single Page Apps and REST Services und überprüfen Sie die entsprechende Beispielanwendung (gleicher Link). Es erklärt, wie Sie tun, was Sie fragen.
Für Scala ist Secure Social wahrscheinlich die beste etablierte Lösung. Unter dem angegebenen Link finden Sie zahlreiche Dokumentationen und Beispiele. Sie können auch eine andere gültige Option Play2-auth betrachten.
Sie finden noch mehr Möglichkeiten auf Play 2 Modules Liste.
Wenn Sie Ihre eigene Lösung backen wollen/müssen, wird es wahrscheinlich immer noch nützlich sein, den Code bestehender Lösungen nach Inspiration und Ideen zu durchsuchen. Nichtsdestotrotz, mein allgemeiner Ratschlag in Bezug auf alles, was mit Sicherheit zu tun hat, ist NICHT, es selbst zu implementieren, es sei denn, Sie benötigen es wirklich (und/oder wissen wirklich, was Sie tun).
BTW, hier gibt es absolut nichts Spezifisches an REST. Sie schützen im Wesentlichen Ihre Controller-Methoden, so dass es keine Rolle spielt, ob ihr Aufruf von einem REST-Aufruf ausgelöst wurde oder nicht.
Wenn wir nur über grundlegende Auth sprechen, benötigen Sie kein externes Modul. Grundsätzlich könnten Sie es mit action composition implementieren.
Here ist ein vollständiges Beispiel darüber. Wenn Sie auch Autorisierung benötigen, können Sie das vorherige Beispiel einfach mit Deadbolt kombinieren. Es ermöglicht Ihnen, Zugriff auf einige Gruppen von Clients bereitzustellen und anderen den Zugriff zu verweigern.
SSL-Unterstützung hat nichts mit der Authentifizierung zu tun. Dies ist jedoch in der Play Documentation
erläutert. Ein Filter könnte ebenfalls verwendet werden. Das Folgende basiert auf Play 2.5.
import org.apache.commons.codec.binary.Base64
override def apply(nextFilter: RequestHeader => Future[Result])
(requestHeader: RequestHeader): Future[Result] = {
val auth = requestHeader.headers.get("Authorization")
val invalidResult = Future.successful(
Unauthorized.withHeaders("WWW-Authenticate" -> """Basic realm="Secured"""")
)
if (auth.isEmpty) {
invalidResult
}
else {
val credentials = new String(Base64.decodeBase64(auth.get.split(" ").drop(1).head.getBytes)).split(":")
if (credentials.length < 2) {
invalidResult
}
else {
for {
authVerify <- verify(credentials(0), credentials(1))
r <- {
if (authVerify) {
nextFilter(requestHeader).map { result: Result => result }
}
else {
invalidResult
}
}
} yield {
r
}
}
}
}
def verify(username: String, password: String): Future[Boolean]
grundsätzlich habe ich die Antwort von @centr genommen und versucht, es ein wenig lesbarer zu machen. Sehen Sie, ob Sie diese Version des gleichen Codes bevorzugen. Gründlich getestet, funktioniert wie erwartet.
def BasicSecured[A](username: String, password: String)(action: Action[A]): Action[A] = Action.async(action.parser) { request =>
val submittedCredentials: Option[List[String]] = for {
authHeader <- request.headers.get("Authorization")
parts <- authHeader.split(' ').drop(1).headOption
} yield new String(decodeBase64(parts.getBytes)).split(':').toList
submittedCredentials.collect {
case u :: p :: Nil if u == username && p == password => action(request)
}.getOrElse {
Future.successful(Unauthorized.withHeaders("WWW-Authenticate" -> """Basic realm="Secured Area""""))
}
}
- 1. HTTP-Standardauthentifizierung über SSL für REST-API
- 2. Play-Framework:! REST-URL mit einem Formparameter
- 3. Probleme mit der Standardauthentifizierung und WCF-REST-Dienstkonfiguration
- 4. Play-Framework und JNotify
- 5. Logback mit Play-Framework
- 6. RESTful auf Play! framework
- 7. OptimisticLockException mit Ebean und Play Framework 2
- 8. Komplexe Joins mit Play Framework und Ebean
- 9. Erlang Web-Framework und SSL?
- 10. Play Framework und Slick Projektarchitektur
- 11. Play Framework und Scala-Import
- 12. Swagger-Datentypmodell in ImplicitParam mit Play Framework
- 13. django rest framework - mit detail_route und detail_list
- 14. Benutzerverwaltung mit Play! Framework 2.0.3
- 15. Play Framework PathBindable mit Abhängigkeitsinjektion
- 16. Objectify mit Play Framework 2
- 17. Browserify/CommonJS mit Play Framework
- 18. SSL-Warnung von Google Play
- 19. Play Evolutions und JPA in Play Framework 2.4
- 20. Parsing einen JSON-Array mit Play-Framework und Java
- 21. Restful (und Stateless) Auth mit Play Framework und Scala
- 22. Play Framework, Routing mit Angular [SCALA]
- 23. Play Framework 2.1.0 & AngularJS-Integration
- 24. play framework atmosphere
- 25. Java Play Framework Fluss
- 26. Play Framework Forms (Java)
- 27. Mehrere truststores in play framework - jvm
- 28. Sind REST-Request-Header mit SSL verschlüsselt?
- 29. Play Framework Asset Pipeline
- 30. Play Framework 2.1.1 Bereitstellungsprobleme
Ich habe eine überarbeitete Kopie dieses Codes in eine separate Antwort hinzugefügt. Danke, die Mechanik funktioniert gut wie erwartet. Ich mag die Verwendung von "" und ":" in String-Splits nicht, da einfache Zeichentrennzeichen ausreichen würden, um Regex-Overhead zu vermeiden. Auch der Filter mit Prädikat ist in einer einzelnen Zeile mit 'collect' Methode ordentlicher.Die Hauptmotivation für das Neuschreiben war der ärgerliche dreieckige Whitespace, da der Code tiefer und tiefer verschachtelt wird. Dies erforderte ein Verständnis :-) –
Passwörter mit ':' würden mehrfach geteilt und zurückgewiesen. – Niklas