在带有DI的Play 2.4中,如何在“安全”特性中使用服务类?

时间:2015-12-11 12:20:52

标签: scala playframework dependency-injection traits playframework-2.4

这是一个authorisation example from Play Documentation(版本2.0.4;我试图找到此文档的更新版本但不能):

trait Secured {

  def username(request: RequestHeader) = request.session.get(Security.username)

  def onUnauthorized(request: RequestHeader) = Results.Redirect(routes.Auth.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))
  }
}
总的来说,这非常简单,我想用这样的东西。

现在,在Play 2.4中,推荐的方法是再使用单例(如上面的UserDAO),而是使用类和运行时DI(参见migration guideDI docs )。

例如,我的服务和存储库类定义如下:

class AuthService @Inject()(accountRepo: AccountRepository) { }

class AccountRepository { }

使用Play 2.4和DI时,建议/“正确”/最简单的方法是获取服务或DAO(在我的情况下为AuthService,或在文档中为UserDAO例如)Secured

等特征

或者您现在是否应该以不同于使用此类特征的方式实施控制器授权?

我可以按照以下方式开展工作:

trait Secured {
  val authService = GuiceUtils.inject[AuthService]    
  // ...
}

使用这样的助手:

object GuiceUtils {
  lazy val injector = new GuiceApplicationBuilder().injector()    
  def inject[T: ClassTag]: T = injector.instanceOf[T]
}

但根据related question中的答案:

  

在Play中,只要应用程序可以直接使用注射器   特质在范围内。但这不是一个好的做法   生产代码。

如果这是真的, 在这个用例中被认为是好习惯吗?

1 个答案:

答案 0 :(得分:16)

我认为最简单的方法是在你的trait中声明authService但保持抽象,然后让扩展它的控制器处理注入(我相信这就是MessagesApi/I18nSupport注入工作的方式)。所以你可以这样做:

trait Secured {
  val authService: AuthService
  ...
}

controller Application @Inject()(override val authService: AuthService) extends Controller with Secured {
  ...
}