我有一个使用securesocial模块的play 2应用程序。在请求中有Identity可用但我需要我的用户对象(扩展身份)传递给我的模板(因为用户包含一些额外的字段)所以对于每个控制器我有如下代码:
def index = SecuredAction { implicit request =>
implicit val currentUser = UsersDAO.Users.findByIdentityId(request.user.identityId).get
Ok(views.html.platform.support.index())
}
基本上对于用户登录的每个控制器的方法,我正在向DB请求获取当前登录的用户,我觉得这很难看。有没有什么办法可以在每个用户会话中加载一次?
更新
我添加了一个部分功能,使事情变得更简单
def loadCurrentUser(f: (User) => Result)(implicit request: SecuredRequest[play.api.mvc.AnyContent]): Result =
(for {
loggedInUser <- UsersDAO.Users.findByIdentityId(request.user.identityId)
} yield f(loggedInUser)).getOrElse(
Redirect(securesocial.controllers.routes.LoginPage.login))
现在控制器的每个方法都是:
def index = SecuredAction { implicit request =>
loadCurrentUser { implicit user =>
Ok(views.html.platform.support.index())
}
}
但我仍然希望有用户请求或在登录后以某种方式传递请求,而不是每次都从DB加载。
答案 0 :(得分:1)
我认为将整个用户存储在会话中是明智的,因为我认为它被认为是不好的做法,并且当用户对象被更改时会使会话更新变得混乱(特别是其他用户,也许是管理员)。
如果您想避免每个请求的数据库调用,我会使用缓存API,但是当用户更改时,仍然需要注意更新/使缓存无效。但至少在缓存中,它们都会在一个地方。
虽然您的loadCurrentUser
功能会确保用户在数据库中存在,但保存.get
的使用情况,我认为它有点多了。如果首先调用了loadCurrentUser
,那么该用户应该存在,如果他们不知道,他们的会话应该已经失效,因此在SecureSocial级别阻止请求。
考虑定义:
implicit def currentUser(implicit request: SecuredRequest[AnyContent]): User = UsersDAO.Users.findByIdentityId(request.user.identityId).get
这会缩短您在currentUser
内对SecuredAction
的通话时间。这也是Play2 Auth使用的技术。
如果你想避免每个请求访问数据库,也许是一个返回缓存用户的函数:
import play.api.cache.Cache
def findByIdentityId(id: Id): Option[User] = ...
def findCachedByIdentityId(id: Id): Option[User] = {
Cache.getAs[User](s"User.$id").orElse{
val user: Option[User] = findByIdentityId(id)
user.foreach(user => Cache.set(s"User.${user.id}"), user)
user
}
}
同样值得研究Action Composition。