In the zentasks example for Play2 we have the method
def isAuthenticated(f: => String => Request[AnyContent] => Result) = {
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
}
What I would like to do is add another method that I could use if I wanted to get the user directly from the database.
It gets a little boring having to add a wrapper in all methods
def method() = isAuthenticated { username => implicit request =>
UserDAO.findOneByEmail(username).map { user =>
Ok(html.user.view(user))
}.getOrElse(Forbidden)
}
I'm new to functional programming and all these =>
is making my head spin :)
Any suggestions?
You can define another method, for example IsAuthenticatedUser
, which would take a parameter of type User => Request[AnyContent] => Result
:
def IsAuthenticatedUser(f: User => Request[AnyContent] => Result) = IsAuthenticated { email => request =>
UserDAO.findOneByEmail(email).map { user =>
f(user)(request)
}.getOrElse(Forbidden)
}
You can then use it like as follows:
def method = IsAuthenticatedUser { user => request =>
Ok(html.user.view(user))
}
This was the final solution
trait Secured {
def username(request: RequestHeader) = request.session.get(Security.username)
def onUnauthorized(request: RequestHeader) = Results.Redirect(routes.Application.login)
def withAuth(f: => String => Request[AnyContent] => Result) = {
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
}
def withUser(f: User => Request[AnyContent] => Result) = withAuth { username => implicit request =>
UserDAO.findOneByUsername(username).map { user =>
f(user)(request)
}.getOrElse(onUnauthorized(request))
}
}
Usage:
object Application extends Controller with Secured {
def index = withAuth { username => implicit request =>
Ok(html.index(username))
}
def user() = withUser { user => implicit request =>
val username = user.username
Ok(html.user(user))
}
}
As you can see, if the session doesn't exist, the user gets redirected to the login page as specified in the trait.
And same goes if the username can't be found in the DAO.
Semi-solution is to encapsulate fetching user data steps into some function and calling it from template level (not on each action), as every template is just a scala function.
Thanks to this approach if you have several actions using the same view (or even layout) you don't have to fetch logged user everytime ie:
in the user view
:
@defining(Application.getLoggedUser){ user =>
@yourlayout("Welcome") {
<h2>Hello @user.name</h2>
...
}
}