玩剪影 - 光滑种子; SecuredAction不会随着TableQuery的更改而执行

时间:2015-08-19 17:24:55

标签: scala playframework slick

我正在为项目使用play-silhouette-slick种子,我需要根据用户的类型将用户添加到不同的表中。但是,如果我在UserDAOImpl.save中更改用于insertUpdate用户的TableQuery,则不会执行下一行的SecuredAction(对于ApplicationController.index),这表明用户尚未经过身份验证。所以通过交换这行代码;

print

对此;

_ <- slickUsers.insertOrUpdate(dbUser)

我的SecuredAction无法执行。有人能指出我正确的方向吗?我的更多代码如下;

_ <-slickAdministrators.insertOrUpdate(dbUser)

DBTableDefinitions

class UserDAOImpl extends UserDAO with DAOSlick {

  import driver.api._

  def find(loginInfo: LoginInfo) = {
    getUserTypeAndID(loginInfo) match {
      case Some((id, userType)) if userType.equals("administrator") => val userQuery = for {
                dbUser <- slickUsers.filter(_.userID === id)
              } yield dbUser
                db.run(userQuery.result.headOption).map { dbUserOption =>
                  dbUserOption.map { user =>
                    Administrator(UUID.fromString(user.userID), loginInfo, user.title, user.firstName, user.lastName, user.email)
                  }
                }
  case None => val userQuery = for {
    dbLoginInfo <- loginInfoQuery(loginInfo)
    dbUser <- slickUsers.filter(_.userID === dbLoginInfo.userID)
  } yield dbUser
    db.run(userQuery.result.headOption).map { dbUserOption =>
      dbUserOption.map { user =>
        Administrator(UUID.fromString(user.userID), loginInfo, user.title, user.firstName, user.lastName, user.email)
      }
    }
} 

def getUserTypeAndID(loginInfo: LoginInfo) = {
    val userQuery = for {
      dbLoginInfo <- loginInfoQuery(loginInfo)
    } yield dbLoginInfo
    val dbresult = db.run(userQuery.result.headOption)
    val userOption = Await.result(dbresult, 5 second) 
    userOption map {info => (info.userID, info.userType)}
  }

 def save(user: User) = {
    val dbUser = DBUser(user.userID.toString, user.title, user.firstName, user.lastName, user.email)
    val userType = user.getClass.getTypeName match {
      case "models.Administrator" => "administrator"
    } 
    val loginInfoAction = {
      val retrieveLoginInfo = slickLoginInfos.filter(
        info => info.providerID === user.loginInfo.providerID &&
        info.providerKey === user.loginInfo.providerKey).result.headOption
      val insertLoginInfo = slickLoginInfos += DBLoginInfo(dbUser.userID, user.loginInfo.providerID, user.loginInfo.providerKey, userType)
      for {
        loginInfoOption <- retrieveLoginInfo
        loginInfo <-   loginInfoOption.map(DBIO.successful(_)).getOrElse(insertLoginInfo)
      } yield loginInfo
    }
    val actions = (for {
      _ <- slickAdministrators.insertOrUpdate(dbUser)
      loginInfo <- loginInfoAction
    } yield ()).transactionally
    // run actions and return user afterwards
    db.run(actions).map(_ => user)
}
}

SignUpController

trait DBTableDefinitions {

  protected val driver: JdbcProfile
  import driver.api._

  case class DBUser (
    userID: String,
title: Option[String],
firstName: Option[String],
lastName: Option[String],
email: Option[String]
  )

  class Users(tag: Tag) extends Table[DBUser](tag, "user") {
    def userID = column[String]("userid", O.PrimaryKey)
    def title = column[Option[String]]("title")
    def firstName = column[Option[String]]("firstname")
    def lastName = column[Option[String]]("lastname")
    def email = column[Option[String]]("email")
    def * = (userID, title, firstName, lastName, email) <> (DBUser.tupled,     DBUser.unapply)
  }

  class Administrators(tag: Tag) extends Table[DBUser](tag, "administrators") {
    def userID = column[String]("userid", O.PrimaryKey)
def title = column[Option[String]]("title")
def firstName = column[Option[String]]("firstname")
def lastName = column[Option[String]]("lastname")
def email = column[Option[String]]("email")
def * = (userID, title, firstName, lastName, email) <> (DBUser.tupled, DBUser.unapply)
  }

case class DBLoginInfo (
     userID: String,
     providerID: String,
     providerKey: String,
     userType: String
  )

  class LoginInfos(tag: Tag) extends Table[DBLoginInfo](tag, "logininfo") {
    def userID = column[String]("userid", O.PrimaryKey)
    def providerID = column[String]("providerid")
def providerKey = column[String]("providerkey")



 def userType = column[String]("usertype")
    def * = (userID, providerID, providerKey, userType) <> (DBLoginInfo.tupled, DBLoginInfo.unapply)
  }



case class DBPasswordInfo (
    hasher: String,
    password: String,
    userID: String
  )

  class PasswordInfos(tag: Tag) extends Table[DBPasswordInfo](tag, "passwordinfo") {
    def hasher = column[String]("hasher")
    def password = column[String]("password")
    def userID = column[String]("userid")
    def * = (hasher, password, userID) <> (DBPasswordInfo.tupled, DBPasswordInfo.unapply)
  }

  // table query definitions
  val slickUsers = TableQuery[Users]
  val slickAdministrators = TableQuery[Administrators]
  val slickLoginInfos = TableQuery[LoginInfos]
  val slickPasswordInfos = TableQuery[PasswordInfos]

  // queries used in multiple places
  def loginInfoQuery(loginInfo: LoginInfo) = 
    slickLoginInfos.filter(dbLoginInfo => dbLoginInfo.providerID === loginInfo.providerID && dbLoginInfo.providerKey === loginInfo.providerKey)

}

的ApplicationController

class SignUpController @Inject() (
  val messagesApi: MessagesApi,
  val env: Environment[User, CookieAuthenticator],
  userService: UserService,
  authInfoRepository: AuthInfoRepository,
  passwordHasher: PasswordHasher)
  extends Silhouette[User, CookieAuthenticator] {

  /**
   * Registers a new user.
   *
   * @return The result to display.
   */
  def signUp(userType: String) = Action.async { implicit request =>
    SignUpForm.form.bindFromRequest.fold(
      form => Future.successful(BadRequest(views.html.signUp(form))),
      data => {
        val loginInfo = LoginInfo(CredentialsProvider.ID, data.email)
        userService.retrieve(loginInfo).flatMap {
          case Some(user) =>
            Future.successful(Redirect(routes.ApplicationController.signUp()).flashing("error" -> Messages("user.exists")))
          case None =>
            val authInfo = passwordHasher.hash(data.password)
            val user = getUser(userType, data, loginInfo)

            for {
              user <- userService.save(user)
              authInfo <- authInfoRepository.add(loginInfo, authInfo)
            //shouldn't need below data -> it creates cookie info to continue as the user added
              authenticator <- env.authenticatorService.create(loginInfo)
              value <- env.authenticatorService.init(authenticator)
              result <- env.authenticatorService.embed(value, Redirect(routes.ApplicationController.index()))
            } yield {
              env.eventBus.publish(SignUpEvent(user, request, request2Messages))
              env.eventBus.publish(LoginEvent(user, request, request2Messages))
              result
            }
        }
      }
    )
  }

  /**
   * Creates a new user according to the specified userType.
   *
   * @param userType the type of user required
   * @param data the data from the SignUpForm
   * @param loginInfo the users loginInfo
   * @return an instance of a User.
   */
  def getUser(userType: String, data: SignUpForm.Data, loginInfo: LoginInfo): User = userType match{
    case "administrator" => Administrator(
                    userID = UUID.randomUUID(),
                    loginInfo = loginInfo,
                    title = Some(data.title),
                    firstName = Some(data.firstName),
                    lastName = Some(data.lastName),
                    email = Some(data.email)
                  )
  }
}

如果我在UserDAOImpl.save中更改了那一行,上面的代码就可以了。

1 个答案:

答案 0 :(得分:0)

问题是我没有在UserDAOImpl中实现一个方法来根据LoginInfo在administrators表中查找用户。所以加上这个;

  def find(loginInfo: LoginInfo) = {
    getUserTypeAndID(loginInfo) match {
      case Some((id, userType)) if userType.equals("administrator") => val userQuery = for {
                dbUser <- slickAdministrators.filter(_.userID === id)
              } yield dbUser
                db.run(userQuery.result.headOption).map { dbUserOption =>
                  dbUserOption.map { user =>
                    Administrator(UUID.fromString(user.userID), loginInfo, user.title, user.firstName, user.lastName, user.email)
                  }
                }
  case None => val userQuery = for {
    dbLoginInfo <- loginInfoQuery(loginInfo)
    dbUser <- slickUsers.filter(_.userID === dbLoginInfo.userID)
  } yield dbUser
    db.run(userQuery.result.headOption).map { dbUserOption =>
      dbUserOption.map { user =>
        Administrator(UUID.fromString(user.userID), loginInfo, user.title, user.firstName, user.lastName, user.email)
      }
    }
}

即行

dbUser <- slickAdministrators.filter(_.userID === id)

现在,SecuredAction按照预期为有效用户执行。我没有意识到这个方法被要求对SecuredAction进行身份验证(或者我在这个问题上错了,而且它是从其他地方调用的),所以如果有人能够进一步解释它会是真的很有帮助 - 这让我整天都在排序!