Create Environment using Compile Time Injection in Play


#1

I am trying to create the Environment in Silhouette using Compile Time Injection but am unable to. All the examples I have seen use runtime DI but that is not what I want to do.

I have defined the Identity and Authenticator as follows

trait SessionEnv extends Env {
  type I = User
  type A = SessionAuthenticator
}

Next, I suppose I have to create the Environment. For that, I have written the following code but am stick as I do not understand how to pass the different parameters expected by Environment’s apply method

Environment companion object’s apply method has signature

def apply[E <: Env](
  identityServiceImpl: IdentityService[E#I],
  authenticatorServiceImpl: AuthenticatorService[E#A],
  requestProvidersImpl: Seq[RequestProvider],
  eventBusImpl: EventBus
)

I know that I have to provide the implementation of IdentityService. I have done so as follows

class UserService @Inject()(userDao:UsersRepository) extends IdentityService[User] {...}

User is defined as follows:

case class UserProfile(
  loginInfo:LoginInfo,
  confirmed: Boolean,
  email:Option[String],
  firstName: Option[String],
  lastName: Option[String],
  passwordInfo:Option[PasswordInfo]
  //oauth1Info: Option[OAuth1Info],
  //avatarUrl: Option[String]) {
)

//representation of a user. A user has an Id and a profile

case class User (id:UUID, profile:UserProfile)

For other values, I thought that I could use the code in the implementation section of the library. I tried

val sessionEnv = com.mohiva.play.silhouette.api.Environment[SessionEnv](new UserService(userRepository),SessionAuthenticatorService() ,CredentialsProvider(),EventBus())

but I get error om.mohiva.play.silhouette.impl.authenticators.SessionAuthenticatorService.type does not take parameters.

I removed the () but got error found : SessionAuthenticatorService.type [error] required: AuthenticatorService[components.SessionEnv#A]


#2

Hi,

The class SessionAuthenticatorService is not a case class, so you must instantiate it with the new keyword.

Brest regards,
Christian


#3

Hi,

there exists also an example which uses MacWire for DI: https://github.com/holandajunior/play-silhouette-macwire-mongodb/blob/master/app/modules/BuiltInComponentModule.scala

Best regards,
Christian


#4

Thanks. I was able to make some breakthroughs and was able to compile the code. However, my concerns is I might not have instantiated Silhouette classes correctly or might have written redundant code. Could you please look at the following code and let me know if this is how it is suppose to be written. Note that I am using compile time injection. This is my Apploader.scala. I am not using Macwire or some other framework. I am creating classes the old fashioned way.

import com.mohiva.play.silhouette.api.actions._
import com.mohiva.play.silhouette.api.{EventBus, SilhouetteProvider}

import com.mohiva.play.silhouette.api.crypto.CrypterAuthenticatorEncoder
import com.mohiva.play.silhouette.api.util.Clock
import com.mohiva.play.silhouette.crypto.{JcaCrypter, JcaCrypterSettings, JcaSigner, JcaSignerSettings}
import com.mohiva.play.silhouette.impl.authenticators.{CookieAuthenticatorService, CookieAuthenticatorSettings}
import com.mohiva.play.silhouette.impl.util.{DefaultFingerprintGenerator, SecureRandomIDGenerator}
import components._
import play.api.mvc.DefaultCookieHeaderEncoding
import controllers._
import play.api._
import services.db.cassandra.UserService
import play.filters.csrf._
import services.AtomicCounter
import play.api.ApplicationLoader.Context
import play.filters.HttpFiltersComponents
import router.Routes


class AppLoader extends ApplicationLoader {

  override def load(context: ApplicationLoader.Context): Application = {
    LoggerConfigurator(context.environment.classLoader).foreach {
      _.configure(context.environment, context.initialConfiguration, Map.empty)
    }
    new AppComponents(context).application
  }
}

class AppComponents (context: Context) extends BuiltInComponentsFromContext(context)
  with CassandraRepositoryComponents
  with HttpFiltersComponents
  with AssetsComponents
  with CSRFComponents
  /*with SilhouetteComponents*/{ //TODOM - Would prefer SilhouetteComponent but creating an Environment requires IdentityService.  UserService is an IdentifyService but it requires userRepository which is created here. Need to resolve this cross dependence

  val userIdentityService = new UserService(userRepository) //responsible for retrieving user information (eg email id) from a database

  val config =  CookieAuthenticatorSettings() 
  val fingerprintGenerator = new DefaultFingerprintGenerator(false)
  val idGenerator = new SecureRandomIDGenerator()
  val clock:Clock = Clock()
  val signer= new JcaSigner(new JcaSignerSettings("someSigner"))
  val crypter = new JcaCrypter(new JcaCrypterSettings("someCrypter"))
  val authenticatorEncoder = new CrypterAuthenticatorEncoder(crypter)
  val cookieHeaderEncoding= new DefaultCookieHeaderEncoding()
  val authenticatorService = new CookieAuthenticatorService(config, None, signer, cookieHeaderEncoding, authenticatorEncoder, fingerprintGenerator, idGenerator, clock)

  val cookieEnv = com.mohiva.play.silhouette.api.Environment[CookieEnv](userIdentityService ,authenticatorService,Seq(),EventBus())

  val defaultParser = new mvc.BodyParsers.Default()

  val securedAction = new DefaultSecuredAction(new DefaultSecuredRequestHandler(new DefaultSecuredErrorHandler(messagesApi)), defaultParser )
  val unsecuredAction = new DefaultUnsecuredAction(new DefaultUnsecuredRequestHandler(new DefaultUnsecuredErrorHandler(messagesApi)),defaultParser)
  val userAware = new DefaultUserAwareAction(new DefaultUserAwareRequestHandler(),defaultParser)

  val silhouette = new SilhouetteProvider[CookieEnv](cookieEnv,securedAction,unsecuredAction,userAware)
  lazy val userRepositoryController = new UserController(userRepository, controllerComponents)
  lazy val homeController = new HomeController(controllerComponents, csrfAddToken,csrfCheck,silhouette) //using Silhouette in only one controller for the moment

  lazy val countController = new CountController(controllerComponents,new AtomicCounter())
  lazy val asyncController = new AsyncController(controllerComponents, actorSystem)

  lazy val userWSRoutes = new WSRouters.User.UserRouter(userRepositoryController) //TODOM - whatam i doing here?

  lazy val router = new Routes(httpErrorHandler, homeController,userWSRoutes, countController,asyncController, assets)

}

#5

Please could you format your code correctly. The editor supports formatting of code snippets.


#6

Tried but couldn’t find how to format the code in the editor. Is there a keyboard shortcut (eg Ctrl K in Stack Overflow or ``) which I need to use?


#7

It uses markdown. So you can use tripple backticks as described here: https://help.github.com/articles/creating-and-highlighting-code-blocks/

Or you can use Ctrl + Shift + C


#8

For some reason, ``` didn’t work but Ctrl + Shift + C was easy! Done.


#9

Looks good to me :+1:


#10

Many thanks for checking it


#11

Hi Christian

I have opened an issue. I created my existing project on a new laptop but I am getting the following error. Could you please take a look.

com.atlassian.jwt#jwt-core;1.6.1: not found

thanks

Manu

Mail](https://go.microsoft.com/fwlink/?LinkId=550986) for Windows 10


#12

Resolved it by adding jcenter repo in build.sbt

Mail](https://go.microsoft.com/fwlink/?LinkId=550986) for Windows 10