如何将用户传递给每个请求?

时间:2014-06-19 07:59:58

标签: playframework-2.0 securesocial

我有一个使用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加载。

1 个答案:

答案 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