gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 17:35:34 25 4
gpt4 key购买 nike

简单地说:我的应用程序使用 Play web framework版本 2.5.1。我想使用the Deadbolt authorization system ,和Slick访问我的数据库中的用户授权信息。我怎样才能做到这一点? Deadbolt 专为 Play 打造,Play 配有开箱即用的集成 Slick,因此即使不是很容易,也应该是可能的。

基于"Integrating Deadbolt"从 Deadbolt 文档中,我扩展了 DeadboltHandler特征。其摘要getSubject()方法似乎是进行数据库查询的地方(如the documentation所示,但没有任何示例)。该方法接收 AuthenticatedRequest 作为参数并返回Subject ,基本上是经过身份验证的用户 ID,以及角色和权限(授权)。

我被困住了,因为 Play 带有 Slick integration ,该文档仅描述如何在 Play Controller 中使用它。 (注意,我想使用依赖注入(inject)来执行此操作,因为使用全局查找已被弃用并且容易出错)

我在 Controller 中成功使用Deadbolt来限制对某些资源的访问,但 Controller 似乎不适合Deadbolt进行数据库查询以获取授权详细信息(如果是的话,那么 DeadboltHandler 将毫无意义)。 Controller 构造函数签名定义类似于(注意 Controller 访问存储 Web 内容的默认数据库而不是授权数据库):

class Application @Inject()(
dbConfigProvider: DatabaseConfigProvider,
playConfig: play.api.Configuration,
deadbolt: DeadboltActions
) extends Controller {

这有效。然而,类似地注释 DeadboltHandler扩展名 @Inject无法提供对数据库的流畅访问:

class AuthHandler @Inject()(@play.db.NamedDatabase("auth") dbConfigProvider: DatabaseConfigProvider)
extends DeadboltHandler {

结果是

not enough arguments for constructor AuthHandler: (dbConfigProvider: play.api.db.slick.DatabaseConfigProvider)services.AuthHandler.
Unspecified value parameter dbConfigProvider.

显然,Play 为 Controller 做了一些特殊的事情,因此 @Inject注释有效,但我对此缺乏理解。我认为这是使用注入(inject)器而不是 new 构建 Controller 的本质。关键字,但我通过 Play 源代码的搜索未能告诉我到底发生了什么。如果我能找到这一点,也许我可以模仿该技术来构建 DeadboltHandler .

我发现游戏附带了类似 GuiceInjector 的类和 GuiceInjectorBuilder ,这听起来好像它们可能是解决方案的一部分,但我的实验尚未向我展示如何使用它们,以及是否有任何文档说明如何在 DeadboldHandler 的特定上下文中使用它们。扩展名,我错过了。

我发现了上一个问题:Scala (Play 2.4.x) How to call a class with @inject() annotation ,这似乎非常切题。不幸的是,尽管原发帖者提出了六条后续评论,但尚未得到答复。我觉得如果我知道了这个问题的答案,我就会知道这个问题的答案,尽管我的问题非常具体:如何使用PlayDeadbolt彼此顺利(在Scala中)。

最让我困惑的是,这似乎应该是很常见的事情,要么在文档中提到,要么已经在 SO 上被询问过。我未能找到任何此类引用资料通常意味着我正在做一些非常错误的事情,以至于没有其他人有机会谈论它。当然,它似乎应该足够简单,以至于我乐观地希望我错过了一些非常基本的东西,并且我期待着某个好心人告诉我这些知识。

最佳答案

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

这是DeadboltHandler的通用实现;您应该能够将其放入代码中并几乎按原样使用它,因为持久性细节将在稍后处理。

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 类提供对主题持久性的访问。这将 DB 访问与 DeadboltHandler 隔离开来。这非常简单,主要是因为您将使用 Slick 查询填写此内容。

@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 中。

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 的常见问题:

play {
modules {
enabled += be.objectify.deadbolt.scala.DeadboltModule
enabled += modules.CustomBindings
}
}

关于scala - 如何集成Play(Web框架)、Deadbolt(授权)和Slick(数据库访问),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36409098/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com