Awesome
Silhouette Authentication with ReactiveMongo and Play 2
This application is based on Silhouette seed Template:
https://github.com/mohiva/play-silhouette-seed
And Silhouette ReactiveMongo persistence layer:
https://github.com/mohiva/play-silhouette-persistence-reactivemongo
The original template uses an array on memory to authenticate users, to use a MongoDB database instead, follow the step by step example.
Edit build.sbt and add the following dependencies
libraryDependencies ++= Seq(
"org.reactivemongo" %% "play2-reactivemongo" % "0.12.1",
"com.mohiva" %% "play-silhouette-persistence-reactivemongo" % "4.0.1"
)
Add ReactiveMongo configuration to application.conf
play.modules.enabled += "play.modules.reactivemongo.ReactiveMongoModule"
mongodb.uri = "mongodb://localhost:27017/test"
Add the implementation of the different delegables on SilhouetteModule.scala
/**
* Provides the implementation of the delegable OAuth1 auth info DAO.
*
* @param reactiveMongoApi The ReactiveMongo API.
* @param config The Play configuration.
* @return The implementation of the delegable OAuth1 auth info DAO.
*/
@Provides
def provideOAuth1InfoDAO(reactiveMongoApi: ReactiveMongoApi, config: Configuration): DelegableAuthInfoDAO[OAuth1Info] = {
implicit lazy val format = Json.format[OAuth1Info]
new MongoAuthInfoDAO[OAuth1Info](reactiveMongoApi, config)
}
/**
* Provides the implementation of the delegable OAuth2 auth info DAO.
*
* @param reactiveMongoApi The ReactiveMongo API.
* @param config The Play configuration.
* @return The implementation of the delegable OAuth2 auth info DAO.
*/
@Provides
def provideOAuth2InfoDAO(reactiveMongoApi: ReactiveMongoApi, config: Configuration): DelegableAuthInfoDAO[OAuth2Info] = {
implicit lazy val format = Json.format[OAuth2Info]
new MongoAuthInfoDAO[OAuth2Info](reactiveMongoApi, config)
}
/**
* Provides the implementation of the delegable OpenID auth info DAO.
*
* @param reactiveMongoApi The ReactiveMongo API.
* @param config The Play configuration.
* @return The implementation of the delegable OpenID auth info DAO.
*/
@Provides
def provideOpenIDInfoDAO(reactiveMongoApi: ReactiveMongoApi, config: Configuration): DelegableAuthInfoDAO[OpenIDInfo] = {
implicit lazy val format = Json.format[OpenIDInfo]
new MongoAuthInfoDAO[OpenIDInfo](reactiveMongoApi, config)
}
/**
* Provides the implementation of the delegable password auth info DAO.
*
* @param reactiveMongoApi The ReactiveMongo API.
* @param config The Play configuration.
* @return The implementation of the delegable password auth info DAO.
*/
@Provides
def providePasswordInfoDAO(reactiveMongoApi: ReactiveMongoApi, config: Configuration): DelegableAuthInfoDAO[PasswordInfo] = {
implicit lazy val format = Json.format[PasswordInfo]
new MongoAuthInfoDAO[PasswordInfo](reactiveMongoApi, config)
}
Inject ReactiveMongoApi on UserDAOImpl.scala and AuthTokenDAOImpl.scala
class AuthTokenDAOImpl @Inject() (val reactiveMongoApi: ReactiveMongoApi) extends AuthTokenDAO
class UserDAOImpl @Inject() (val reactiveMongoApi: ReactiveMongoApi) extends UserDAO
Specify the collection name on both files
def collection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection("silhouette.user"))
def collection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection("silhouette.token"))
Rename password collections if needed on silhouette.conf
persistence.reactivemongo.collection.OAuth1Info = "silhouette.password"
persistence.reactivemongo.collection.OAuth2Info = "silhouette.password"
persistence.reactivemongo.collection.OpenIDInfo = "silhouette.password"
persistence.reactivemongo.collection.PasswordInfo = "silhouette.password"
And finally rewrite functions on the both classes, for example I will show UserDaoImpl functions
/**
* Finds a user by its login info.
*
* @param loginInfo The login info of the user to find.
* @return The found user or None if no user for the given login info could be found.
*/
def find(loginInfo: LoginInfo): Future[Option[User]] = {
val query = Json.obj("loginInfo" -> loginInfo)
collection.flatMap(_.find(query).one[User])
}
/**
* Finds a user by its user ID.
*
* @param userID The ID of the user to find.
* @return The found user or None if no user for the given ID could be found.
*/
def find(userID: UUID): Future[Option[User]] = {
val query = Json.obj("userID" -> userID)
collection.flatMap(_.find(query).one[User])
}
/**
* Saves a user.
*
* @param user The user to save.
* @return The saved user.
*/
def save(user: User): Future[User] = {
collection.flatMap(_.insert(user))
Future.successful(user)
}