This is a simple example of a controller in Play Framework where every action checks the session - if the user is logged in.
object Application extends Controller {
def index = Action { implicit request =>
if (request.session.isEmpty) {
Redirect("/login")
} else {
Ok(views.html.index("index"))
}
}
def about = Action { implicit request =>
if (request.session.isEmpty) {
Redirect("/login")
} else {
Ok(views.html.index("about"))
}
}
}
I'd like to handle the session checking in the constructor instead of every action method, but I just don't know how? It should look something like this:
object Application extends Controller {
//This is where the constructor would check if session exists
//and if not - redirect to login screen
def index = Action {
Ok(views.html.index("index"))
}
def about = Action {
Ok(views.html.index("about"))
}
}
Is this possible and if so then how?
My stack is Play Framework 2.2.1, Scala 2.10.3, Java 1.8.0-ea 64bit
UPDATE - SOLVED Thanks for all your ideas, solution is now found, see my answer.
You could take advantage of Action Composition to achieve this. From the documentation:
import play.api.mvc._
class AuthenticatedRequest[A](val username: String, request: Request[A]) extend WrappedRequest[A](request)
object Authenticated extends ActionBuilder[AuthenticatedRequest] {
def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) =>Future[SimpleResult]) = {
request.session.get("username").map { username =>
block(new AuthenticatedRequest(username, request))
} getOrElse {
Future.successful(Forbidden)
}
}
}
And then you could simply do:
def index = Authenticated {
Ok(views.html.index("index"))
}
Alternatively you could set up a filter instead (as @Robin Green suggested) like so:
object AuthFilter extends Filter {
override def apply(next: RequestHeader => Result)(rh: RequestHeader): Result = {
rh.session.get("username").map { user =>
next(rh)
}.getOrElse {
Redirect("/login")
}
}
In Global.scala scala, add
override def doFilter(action: EssentialAction) = AuthFilter(action)
For more on Filters, see the official docs
Solution is to use Action Composition and create a custom action.
Auth.scala:
package core
import play.api.mvc._
import scala.concurrent._
import play.api.mvc.Results._
object AuthAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[SimpleResult]) = {
if (request.session.isEmpty) {
//authentication condition not met - redirect to login page
Future.successful(Redirect("/login"))
} else {
//proceed with action as normal
block(request)
}
}
}
Application.scala:
package controllers
import play.api._
import play.api.mvc._
import core._
object Application extends Controller {
def index = AuthAction {
Ok(views.html.index("You are logged in."))
}
}
Take a look at Deadbolt: https://github.com/schaloner/deadbolt-2 . There are exhaustive examples and guides.
Works perfectly in my Play 2 project.
You could use a Filter
, which applies to every request in the application. However, then you would need to have some code in that Filter
to allow certain URLs to be accessed without a valid session, otherwise then the user would not be able to login in the first place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With