How to extend the Play2 scala zentasks authenticat

2020-07-30 01:09发布

问题:

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?

回答1:

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))
}


回答2:

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.



回答3:

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>
        ...
    } 
}