我是这个认证领域的新手。我搜索了很多,但无法找到一种方法来验证对Play服务器的REST调用。有哪些方法和最佳实践?
答案 0 :(得分:11)
一种非常简单的方法是使用Action Composition。有关示例,请查看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与基本身份验证无关。您可以直接或通过前端HTTP服务器(如ngnix)将HTTPS用于API。 Play文档中有关于此主题的非常好的细节。
答案 1 :(得分:5)
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""""))
}
}
答案 2 :(得分:4)
如果我们只是谈论基本身份验证,您就不需要任何外部模块。基本上,您可以使用action composition来实现它。
Here就是一个完整的例子。
如果您还需要授权,则只需将前一个示例与Deadbolt结合使用即可。它允许您提供对某些客户端组的访问权限,并拒绝访问其他客户端。
SSL支持与身份验证无关。但是,Play Documentation
中对此进行了解释答案 3 :(得分:3)
阅读以下自述文章:Securing Single Page Apps and REST Services并查看相应的示例应用程序(相同链接)。 它解释了如何做你要求的事情。
答案 4 :(得分:3)
对于Scala,Secure Social可能是最好的解决方案。您将在给定链接中找到大量文档和示例。 您还可以查看Play2-auth作为另一个有效选项。
您会在Play 2 Modules列表中找到更多可能性。
如果您想/需要烘焙自己的解决方案,那么查看现有解决方案的代码以获取灵感和想法可能仍然有用。尽管如此,我对与安全相关的任何事情的一般建议都不是自己实现它,除非你真的需要它(和/或真的知道你在做什么)。
顺便说一句,这里绝对没有关于REST的具体内容。您实际上是在保护您的控制器方法,因此无论是否由REST调用触发它们都无关紧要。答案 5 :(得分:3)
也可以使用过滤器。以下内容基于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]