【发布时间】:2015-06-12 01:21:33
【问题描述】:
我是这个认证领域的新手。我进行了很多搜索,但无法找到一种方法来验证对 Play 服务器进行的 REST 调用。有哪些不同的方法和最佳实践?
【问题讨论】:
标签: scala playframework playframework-2.0 scala-collections typesafe-activator
我是这个认证领域的新手。我进行了很多搜索,但无法找到一种方法来验证对 Play 服务器进行的 REST 调用。有哪些不同的方法和最佳实践?
【问题讨论】:
标签: scala playframework playframework-2.0 scala-collections typesafe-activator
一个非常简单的方法是使用动作组合。有关示例,请查看 Guillaume Bort 提供的 Gist: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 文档中有关于此主题的非常好的详细信息。
【讨论】:
collect 方法在一行上更整洁。重写的主要动机是令人讨厌的三角形空白,因为代码嵌套越来越深。这需要理解:-)
: 的密码将被多次拆分并被拒绝。
基本上,我从@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""""))
}
}
【讨论】:
如果我们只是在谈论基本身份验证,您不需要任何外部模块。基本上,您可以使用action composition 来实现它。
Here 就是一个完整的例子。
如果您还需要授权,您可以简单地将前面的示例与Deadbolt 结合起来。它将允许您提供对某些客户端组的访问权限并拒绝其他客户端的访问权限。
SSL 支持与身份验证没有任何关系。不过,在Play Documentation中有解释
【讨论】:
阅读以下自述文件/文章:Securing Single Page Apps and REST Services 并查看相应的示例应用程序(相同链接)。 它解释了如何按照您的要求进行操作。
【讨论】:
对于 Scala,Secure Social 可能是最好的既定解决方案。您将在给定的链接中找到大量文档和示例。 您还可以查看 Play2-auth 作为另一个有效选项。
您会在Play 2 Modules 列表中找到更多可能性。
如果您想要/需要烘焙自己的解决方案,查看现有解决方案的代码以获取灵感和想法可能仍然有用。尽管如此,我对与安全相关的任何事情的一般建议是不要自己实施,除非你真的需要它(和/或真的知道你在做什么)。
顺便说一句,这里绝对没有关于 REST 的具体内容。您实际上是在保护您的控制器方法,因此它们的调用是否由 REST 调用触发并不重要。
【讨论】:
也可以使用过滤器。以下内容基于 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]
【讨论】: