To set a cookie you usually manipulate the result in an action like Ok().withCookies(…)
.
I created an AuthenticatedAction extends ActionBuilder[AuthenticatedRequest]
and need to update the expiry date of a user's cookie by setting a new cookie with a new maxAge sometimes. I cannot figure out how to do this, because I can't find a way to manipulate the result.
Within the invokeBlock
function I call block(new AuthenticatedRequest(identity, request))
, which returns a Future[SimpleResult] and I cannot use withCookies()
on a Future[SimpleResult]
.
Here's my custom AuthenticatedAction:
class AuthenticatedRequest[A](val identity: Identity, request: Request[A]) extends WrappedRequest[A](request)
object AuthenticatedAction extends ActionBuilder[AuthenticatedRequest] {
def redirectToLogin = {
Redirect("/login")
}
def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[SimpleResult]) = {
request.cookies.get("mycookie").map { cookie =>
val maybeIdentity = Auth.validateAndTouchTokenAndGetUser(cookie.value)
maybeIdentity.map { identity =>
// If it's a persistent session, update timestamp by sending a new cookie sometimes!
// To simplify this example, assume we always want to set a new cookie.
val futureResult = block(new MaybeAuthenticatedRequest(maybeIdentity, request))
// What next?
val newMaxAge = 1234
// ???result???.withCookies(Cookie("mycookie", cookie.value, newMaxAge))
} getOrElse {
// Respond with redirect to login and delete cookie and a warning message
Future.successful(
redirectToLogin
.discardingCookies(DiscardingCookie("mycookie"))
.flashing("warning" -> "Your session has expired. Please sign in again.")
)
}
} getOrElse {
// Respond with redirect to login
Future.successful(redirectToLogin)
}
}
}
Ok
is a SimpleResult
as well. You cannot set cookies for a Future[SimpleResult]
but you can do like this:
val futureResult: Future[SimpleResult] = ...
futureResult.map(_.withCookies(Cookie("mycookie", cookie.value, newMaxAge))
Update for Blankman
:
The simpliest case for responding with cookies is like this:
def myAction = Action {
.....
Ok(response).withCookies(Cookie("cookie", cookieValue, maxAge))
}
This way you can compose your more complex Action like this (example from my project):
def safe(doSafe: Request[AnyContent] => Future[SimpleResult]): Action[AnyContent] = Action.async { implicit request =>
try {
doSafe(request).map(_.withCookies(Cookie("mycookie", cookie.value, newMaxAge))
} catch {
case e: Exception =>
e.printStackTrace()
//custom failure response here
}
}
Usage:
def someAction = safe { implicit request =>
.... //something that returns a Future[SimpleResult]
}