我正在为项目使用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中更改了那一行,上面的代码就可以了。
答案 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进行身份验证(或者我在这个问题上错了,而且它是从其他地方调用的),所以如果有人能够进一步解释它会是真的很有帮助 - 这让我整天都在排序!