Play Framework REST с базовой аутентификацией и SSL
Я новичок в этой области аутентификации. Я много искал, но не смог найти способ аутентификации остальных вызовов, сделанных на Play server. Каковы различные способы и наилучшая практика?
6 ответов
очень простой способ-использовать состав действия. Для образца, взгляните на эту суть обеспеченную Guillaume Bort:https://gist.github.com/guillaumebort/2328236. Если вы хотите использовать его в асинхронном действии, вы можете написать что-то вроде:
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 не имеет ничего общего с базовой аутентификацией. Вы можете использовать HTTPS для API напрямую или через интерфейсный HTTP-сервер, например ngnix. Есть довольно хорошие детали в документации Play об этом предмет:.
в основном, я взял ответ от @centr и попытался сделать его немного более читаемым. Посмотрите, предпочитаете ли вы эту версию того же кода. Тщательно проверено, работает, как ожидалось.
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""""))
}
}
прочитайте следующее Readme / article:защита одностраничных приложений и служб REST и проверить соответствующий образец ходатайства (та же ссылка). Это объясняет, как сделать то, о чем вы просите.
Для Scala, Безопасность Социальная вероятно самое лучшее estabilished разрешение. Вы найдете множество документации и примеров по данной ссылке. Вы также можете взглянуть на методу play2-авт как еще один допустимый вариант.
вы найдете еще больше возможностей на Играть 2 Модуля список.
Если вы хотите / должны испечь свое собственное решение, вероятно, все равно будет полезно заглянуть в код существующих решений для вдохновения и помыслы. Тем не менее, мой общий совет ко всему, что связано с безопасностью, - не реализовывать его самостоятельно, если вы действительно в этом не нуждаетесь (и/или действительно знаете, что делаете).
кстати, здесь нет абсолютно ничего конкретного об отдыхе. Вы по существу защищаете свои методы контроллеров, поэтому не имеет значения, был ли их вызов вызван вызовом REST или нет.
Если мы просто говорим о basic auth, вам не нужен никакой внешний модуль. В принципе, вы можете реализовать его с помощью состав действий.
здесь является полным примером об этом.
Если Вам также нужен авторизация, вы можете просто объединить предыдущий пример с замок. Это позволит вам предоставить доступ к одной группе клиентов и запретить доступ к другим.
протокол SSL поддержка не имеет ничего общего с проверкой подлинности. Однако, объясняется в Играть Документацией
фильтр также может быть использован. Следующее основано на игре 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]