首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何集成Play (web框架)、Deadbolt (授权)和Slick (数据库访问)

如何集成Play (web框架)、Deadbolt (授权)和Slick (数据库访问)
EN

Stack Overflow用户
提问于 2016-04-04 17:28:54
回答 1查看 1.1K关注 0票数 6

简单地说:我的应用程序使用了播放web框架版本2.5.1。我想使用死螺栓授权系统浮油来访问我数据库中的用户授权信息.我该怎么做?死气沉沉的螺栓是专门为游戏而做的,而游戏是带着机灵的集成的,所以它应该是可能的,如果不是很容易的话。

基于死螺栓文档中的“整合死神”,我扩展了DeadboltHandler特性。它的抽象getSubject()方法似乎是执行数据库查询的地方( 文献资料是这样说的,但没有任何示例)。该方法作为参数接收AuthenticatedRequest并返回Subject (基本上是经过身份验证的用户id)以及角色和权限(授权)。

我被困住了,因为虽然Play附带了光滑积分,但是文档只描述了如何在Play控制器中使用它。(注意,我希望使用依赖项注入来实现这一点,因为不推荐使用全局查找,并且容易出错)

我成功地在控制器中使用死螺栓来限制对某些资源的访问,但对于Deadbolt来说,对授权细节的数据库查询(如果是的话,那么DeadboltHandler将是无目的的),这似乎是一个错误的位置。控制器构造函数签名定义类似于(注意,控制器访问存储web内容的默认数据库,而不是授权数据库):

代码语言:javascript
复制
class Application @Inject()(
  dbConfigProvider: DatabaseConfigProvider,
  playConfig: play.api.Configuration,
  deadbolt: DeadboltActions
) extends Controller {

这是可行的。但是,使用DeadboltHandler@Inject扩展进行类似的注释无法提供对数据库的灵活访问:

代码语言:javascript
复制
class AuthHandler @Inject()(@play.db.NamedDatabase("auth") dbConfigProvider: DatabaseConfigProvider)
  extends DeadboltHandler {

其结果是

代码语言:javascript
复制
not enough arguments for constructor AuthHandler: (dbConfigProvider: play.api.db.slick.DatabaseConfigProvider)services.AuthHandler.
Unspecified value parameter dbConfigProvider.

显然,Play为控制器做了一些特殊的事情,因此@Inject注释可以工作,我对此缺乏理解。我猜想这是使用注入器而不是new关键字构造控制器的本质,但是我在Play源代码中的搜索没有告诉我到底发生了什么。如果我能找到它,也许我可以模仿这个技术来构造一个DeadboltHandler

我看到了GuiceInjectorGuiceInjectorBuilder这样的类,它们听起来好像是解决方案的一部分,但是我的实验还没有告诉我如何使用它们,如果有关于如何在DeadboldHandler扩展的特定上下文中使用它们的文档,我就会忽略它。

我发现了前面的一个问题:Scala (Play 2.4.x)如何使用@inject()注释调用类,这似乎是非常有意义的。不幸的是,尽管有半打的后续评论,从最初的海报,它还没有得到答复。我觉得,如果我有这个问题的答案,我会得到这个问题的答案,虽然我的问题是非常具体的:如何使用游戏和死神螺栓,与其他人(在Scala)。

最让我困惑的是,这似乎是一种应该足够普遍的东西,要么在文档中提到,要么已经被问到了。我找不到任何这样的参考资料,这通常意味着我做了一件很特别的错事,以至于没有其他人有机会谈论它。显然,这似乎应该足够简单,我乐观地希望我错过了一些非常基本的东西,我期待着某个善良的灵魂告诉我这方面的知识。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-08 12:45:44

正如您在问题中所指出的,检索用户的位置在DeadboltHandler.getSubject中。实际上,您可以将特定于数据库的代码移动到它自己的类中,因此在本例中,这就是我所做的。

这是DeadboltHandler的一个通用实现;您应该能够将它放到代码中并像- is一样使用它,因为持久性的细节将在后面处理。

代码语言:javascript
复制
import javax.inject.{Inject, Singleton}

import be.objectify.deadbolt.scala.models.Subject
import be.objectify.deadbolt.scala.{AuthenticatedRequest, DeadboltHandler, DynamicResourceHandler}
import models.{LogInForm, User}
import play.api.mvc.{Request, Result, Results}
import play.twirl.api.HtmlFormat
import views.html.security.denied

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

@Singleton
class MyDeadboltHandler @Inject() (authSupport: AuthSupport) extends DeadboltHandler {

  override def beforeAuthCheck[A](request: Request[A]): Future[Option[Result]] = Future {None}

  override def getDynamicResourceHandler[A](request: Request[A]): Future[Option[DynamicResourceHandler]] = Future {None}

  /**
    * Get the current user.
    *
    * @param request the HTTP request
    * @return a future for an option maybe containing the subject
    */
  override def getSubject[A](request: AuthenticatedRequest[A]): Future[Option[Subject]] = 
    Future {
      request.subject.orElse {
        // replace request.session.get("userId") with how you identify the user
        request.session.get("userId") match {
          case Some(userId) => authSupport.getUser(userId)
          case _ => None
        }
      }}

  /**
    * Handle instances of authorization failure.
    *
    * @param request the HTTP request
    * @return either a 401 or 403 response, depending on the situation
    */
  override def onAuthFailure[A](request: AuthenticatedRequest[A]): Future[Result] = {
    def toContent(maybeSubject: Option[Subject]): (Boolean, HtmlFormat.Appendable) =
      maybeSubject.map(subject => subject.asInstanceOf[User])
      .map(user => (true, denied(Some(user))))
      .getOrElse {(false, views.html.security.logIn(LogInForm.logInForm))}

    getSubject(request).map(maybeSubject => toContent(maybeSubject))
    .map(subjectPresentAndContent =>
      if (subjectPresentAndContent._1) Results.Forbidden(subjectPresentAndContent._2)
      else Results.Unauthorized(subjectPresentAndContent._2))
  }
}

现在,进入数据库的需要已减少到尚未将主题放入请求中的情况。注意有关用标识用户的方式替换request.session.get("userId")的注释。

然后,AuthSupport类提供对主题持久性的访问。这将数据库访问与DeadboltHandler隔离开来。这很简单,主要是因为您将使用精巧的查询来填充它。

代码语言:javascript
复制
@Singleton
class AuthSupport @Inject()(dbConfigProvider: DatabaseConfigProvider) {
    // set up your usual Slick support

    // use Slick to get the subject from the database
    def getUser(userId: String): Option[User] = ???
}

要公开这一点,您需要创建一个模块并在您的application.conf中注册它。

代码语言:javascript
复制
import be.objectify.deadbolt.scala.DeadboltHandler
import be.objectify.deadbolt.scala.cache.HandlerCache
import security.{AuthSupport, MyDeadboltHandler, MyHandlerCache}
import play.api.inject.{Binding, Module}
import play.api.{Configuration, Environment}

class CustomBindings extends Module  {
  override def bindings(environment: Environment,
                        configuration: Configuration): Seq[Binding[_]] =
    Seq(
         bind[DeadboltHandler].to[MyDeadboltHandler],
         bind[AuthSupport].toSelf,
         // other bindings, such as HandlerCache
       )
}

application.conf中声明它是通常使用play.modules.enabled的事情。

代码语言:javascript
复制
play {
  modules {
    enabled += be.objectify.deadbolt.scala.DeadboltModule
    enabled += modules.CustomBindings
  }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36409098

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档