Play (Scala) 中基于 JSON 令牌授权的自定义操作组合
Custom Action composition to authorize based on JSON token in Play (Scala)
与大多数关于 Action 组合的讨论(例如 this one)不同,我需要在我的 Action 中解析传入的 JSON 请求。这是因为我们的应用程序提供了一个嵌入在 JSON 中的安全令牌(而不是通常在 header 中)。
我想要实现的是:
object AuthenticatedAction extends ActionBuilder[UserRequest] with ActionTransformer[Request, UserRequest] {
// Do something magical here that will:
// 1. parse the inbound request.body.validate[GPToken]
// 2. (do stuff with the token to check authorization)
// 3. if NOT authorized return an HTTP NOTAUTHORIZED or FORBIDDEN
// 4. otherwise, forward the request to the desired endpoint
}
object SomeController extends Controller
val action = AuthenticatedAction(parse.json) { implicit request =>
request.body.validate[SomeRequest] match {
// Do whatever... totally transparent and already authorized
}
}
...
入站 JSON 将始终有一个标记,例如:
{
"token":"af75e4ad7564cfde",
// other parameters we don't care about
}
所以,我想只解析我们想要的(并且 而不是 最终解析复杂的、深度嵌套的 JSON 结构)我可以只拥有一个 GPToken object:
class GPToken(token: String)
object GPToken { implicit val readsToken = Json.reads[GPToken] }
然后在 AuthenticationAction 的 "magic" 中,我可以只反序列化令牌,对数据库执行我的操作以检查授权,然后传递请求或发回 NOTAUTHORIZED。但这就是我迷路的地方...如何获取 json body、解析它并通过我的安全层过滤所有传入请求?
我认为最好将该令牌移动到您的请求中 headers。这样做将允许您使用 Play 的 AuthenticatedBuilder,它是一个 ActionBuilder 来帮助进行身份验证。
如果你能做到这一点,那么你就可以拥有这样的特质:
trait Authentication {
object Authenticated extends play.api.mvc.Security.AuthenticatedBuilder(checkGPToken(_), onUnauthorized(_))
def checkGPToken(request: RequestHeader): Option[User] = {
request.headers.get("GPToken") flatMap { token =>
// Do the check with the token
// Return something about the user that will be available inside your actions
}
}
def onUnauthorized(request: RequestHeader) = {
// Do something when it doesn't pass authorization
Results.Unauthorized
}
}
现在使用控制器,您可以非常简单地创建需要身份验证的操作。
object SomeController extends Controller with Authentication {
def someAction = Authenticated { req =>
// Your user your header check is available
val user = req.user
// Do something in the context of being authenticated
Ok
}
}
与大多数关于 Action 组合的讨论(例如 this one)不同,我需要在我的 Action 中解析传入的 JSON 请求。这是因为我们的应用程序提供了一个嵌入在 JSON 中的安全令牌(而不是通常在 header 中)。
我想要实现的是:
object AuthenticatedAction extends ActionBuilder[UserRequest] with ActionTransformer[Request, UserRequest] {
// Do something magical here that will:
// 1. parse the inbound request.body.validate[GPToken]
// 2. (do stuff with the token to check authorization)
// 3. if NOT authorized return an HTTP NOTAUTHORIZED or FORBIDDEN
// 4. otherwise, forward the request to the desired endpoint
}
object SomeController extends Controller
val action = AuthenticatedAction(parse.json) { implicit request =>
request.body.validate[SomeRequest] match {
// Do whatever... totally transparent and already authorized
}
}
...
入站 JSON 将始终有一个标记,例如:
{
"token":"af75e4ad7564cfde",
// other parameters we don't care about
}
所以,我想只解析我们想要的(并且 而不是 最终解析复杂的、深度嵌套的 JSON 结构)我可以只拥有一个 GPToken object:
class GPToken(token: String)
object GPToken { implicit val readsToken = Json.reads[GPToken] }
然后在 AuthenticationAction 的 "magic" 中,我可以只反序列化令牌,对数据库执行我的操作以检查授权,然后传递请求或发回 NOTAUTHORIZED。但这就是我迷路的地方...如何获取 json body、解析它并通过我的安全层过滤所有传入请求?
我认为最好将该令牌移动到您的请求中 headers。这样做将允许您使用 Play 的 AuthenticatedBuilder,它是一个 ActionBuilder 来帮助进行身份验证。
如果你能做到这一点,那么你就可以拥有这样的特质:
trait Authentication {
object Authenticated extends play.api.mvc.Security.AuthenticatedBuilder(checkGPToken(_), onUnauthorized(_))
def checkGPToken(request: RequestHeader): Option[User] = {
request.headers.get("GPToken") flatMap { token =>
// Do the check with the token
// Return something about the user that will be available inside your actions
}
}
def onUnauthorized(request: RequestHeader) = {
// Do something when it doesn't pass authorization
Results.Unauthorized
}
}
现在使用控制器,您可以非常简单地创建需要身份验证的操作。
object SomeController extends Controller with Authentication {
def someAction = Authenticated { req =>
// Your user your header check is available
val user = req.user
// Do something in the context of being authenticated
Ok
}
}