Note that there are some explanatory texts on larger screens.

plurals
  1. POPlay2.2.x, BodyParser, Authentication, and Future[Result]
    text
    copied!<p>I'm trying to implement authentication in my Play 2.2.1 app, and I can't quite figure out how to make it work with an action that returns a Future[Result].</p> <p>This post describes pretty close to what I'm trying to do, except without returning Future[Result]: </p> <p><a href="https://stackoverflow.com/questions/11104005/play-2-0-framework-using-a-bodyparser-with-an-authenticated-request">Play 2.0 Framework, using a BodyParser with an authenticated request</a></p> <p>How can I get it to work with Futures? I.e. how would I implement this function:</p> <pre><code>def IsAuthenticated(f: =&gt; String =&gt; Request[Any] =&gt; Future[Result]) </code></pre> <p>or, better yet, this function:</p> <pre><code>def IsAuthenticated[A}(b:BodyParser[A])(f: =&gt; String =&gt; Request[Any] =&gt; Future[Result]) </code></pre> <p>which would feed into this function:</p> <p>def AuthenticatedUser(g: Account => Request[AnyContent] => SimpleResult) = IsAuthenticated {...}</p> <p>to wrap asynchronous actions in my controllers?</p> <p>This part I can do:</p> <pre><code> def IsAuthenticated(f: =&gt; String =&gt; Request[AnyContent] =&gt; Future[SimpleResult]) = { Security.Authenticated(email, onUnauthorized) { user =&gt; Action.async(request =&gt; f(user)(request)) } } </code></pre> <p>But if I try to use IsAuthenticated in my wrapper function:</p> <pre><code> def AuthenticatedUser(g: Account =&gt; Request[AnyContent] =&gt; Future[SimpleResult]) = IsAuthenticated { email =&gt; implicit request =&gt; Account.find(email).map { opt =&gt; opt match { case Some(account) =&gt; g(account)(request) case None =&gt; Future(onUnauthorized(request)) } } } </code></pre> <p>(Account.find returns a Future[Option[Account]] 'cause it's a mongodb call that may take some time. The desire to do the future thing right is what's causing me so much grief now)</p> <p>I can't get AuthenticatedUser to satisfy the compiler. It says it's getting a Future[Future[SimpleResult]] instead of a Future[SimpleResult].</p> <p>So, how best to build this whole thing? I need to be able to make authentication wrappers that rely on db calls that are asynchronous. </p> <p>I'm sure I'm just dense and missing something obvious...</p> <p>EDIT: Here's what I ended up with. Thank you Jean for pointing me in the right direction.</p> <p>I found AuthenticatedController while rooting around and it's pretty close to what I'm looking for. I wanted two types of authentication: User (authenticated user) and Administrator (to wrap code for admin tasks).</p> <pre><code>package controllers import models.Account import play.api.mvc._ import scala.concurrent.Future trait Secured { class AuthenticatedRequest[A](val account: Account, request: Request[A]) extends WrappedRequest[A](request) object User extends ActionBuilder[AuthenticatedRequest] { def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) =&gt; Future[SimpleResult]) = { request.session.get("email") match { case Some(email) =&gt; { Account.find(email).flatMap { case Some(account) =&gt; { block(new AuthenticatedRequest(account, request)) } case _ =&gt; Future(Results.Redirect(routes.Index.index())) } } case _ =&gt; Future(Results.Redirect(routes.Index.index())) } } } object Administrator extends ActionBuilder[AuthenticatedRequest] { def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) =&gt; Future[SimpleResult]) = { request.session.get("email") match { case Some(email) =&gt; { Account.find(email).flatMap { case Some(account) =&gt; if (account.admin) { block(new AuthenticatedRequest(account, request)) } else { Future(Results.Redirect(routes.Index.index())) } case _ =&gt; Future(Results.Redirect(routes.Index.index())) } } case _ =&gt; Future(Results.Redirect(routes.Index.index())) } } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload