Difficulty while using play 2.3.10 for Scala with deadbolt 2.3.2
shuroo opened this issue · comments
Hi,
I am using deadbolt-scala , version 2.3.2, with play-framework 2.3.10 (scala version: 2.11.7).
I would like to consult, in order to improve the following code. This is a repeatable issue I have in my code.
And the matter is:
When I use Deadbolt in my play framework controllers, sometimes the authorization check is nested inside the inner request. meaning, that in this part I would like to return Future[Result] and not Action[AnyContent].
Since using deadbolt "dynamic" method to add authorization check returns action[A], I need to use apply[request] to force returning Future[Result].
Also, when the original request asynchronous and has body, the returned type is of type Action[JsValue] , so I need to convert it to Action[AnyContent] using asInstanceOf (in order to use the right apply method that will return the expected Future[Result] type ).
This is not such a nice code, and using asInstanceOf[Request[AnyContent]] is a Scala anti-pattern, please advice me if there is a better way of achieving my goal.
Thanks.
Code Example:
/code
def doRequest() = {
Action.async(parse.json) {
request => {
/** fetch auth_param here **/.flatMap(_ match {
case Some(fetched_param) =>
performOperationWhenValid(auth_param)
case None =>
.....
}.recover {
case e => doRecover(e)
}
}
}
def performOperationWhenValid(auth_param:String) = {
// Authorization check
val allow_or_forbid_action = Dynamic(auth_param:String, "",
new FL_DeadboltHandler(Option(new AuthorizedDynamicResourceHandler))) {
Action.async {
request.body.validate[PerformOperationRequest].fold(
errors =>
Future.successful(BadRequest(formatErrorMessage(errors)))
,
patch_request =>
/*** performOperation here after authorization check is passed successfully... ***/
}
}
allow_or_forbid_action.apply(request.asInstanceOf[AnyContent])
}
I think the easiest way around this issue is to write your own Dynamic
and customize it for your needs. In Deadbolt, the standard implementation of Dynamic
is
def Dynamic[A](name: String,
meta: String = "",
deadboltHandler: DeadboltHandler)
(action: Action[A]): Action[A] = {
Action.async(action.parser) { implicit request =>
deadboltHandler.beforeAuthCheck(request) match {
case Some(result) => result
case _ =>
deadboltHandler.getDynamicResourceHandler(request) match {
case Some(dynamicHandler) =>
if (dynamicHandler.isAllowed(name, meta, deadboltHandler, request)) action(request)
else deadboltHandler.onAuthFailure(request)
case None =>
throw new RuntimeException("A dynamic resource is specified but no dynamic resource handler is provided")
}
}
}
}
In your own implementation, instead of passing in Action[A]
you can either make it generic and pass a function into it, or hard-code it for your Future[Result]
. You then need to change these two lines to handle that type:
if (dynamicHandler.isAllowed(name, meta, deadboltHandler, request)) action(request) /*replace this with your Future[Result] */
else deadboltHandler.onAuthFailure(request)
Thanks. I've added a method similar to Dynamic(...) to handle this case as you suggested.