Frage Wie implementiert man mehrere Silhouette Authenticators?


Ich habe das benutzt Spiel-Silhouette-Samen als Vorlage für meine Bewerbung. In meinem Projekt verwende ich einen Cookie-basierten Authenticator (CookieAuthenticator). Dies funktioniert auch für REST-Aufrufe über JavaScript, die in meine Twirl-Vorlage eingebettet sind, absolut einwandfrei. Jetzt möchte ich jedoch auch REST-Aufrufe programmgesteuert in anderen Clients als einem Browser vornehmen. Als Konsequenz müsste ich die Set-Cookie: authenticator=... Element für jede Antwort und legen Sie es als Teil meiner Anfrage fest. In meinem JavaScript-Snippet, das in meine Twirl-Vorlage eingebettet ist und im Browser gerendert wird, ist das kein Problem, da ich mich damit nicht auseinandersetzen muss, aber für andere Clients (Server etc.) bereitet das Kopfschmerzen.

Ich möchte jetzt ein implementieren JWTAuthenticator zusätzlich zu meinem CookieAuthenticator. Wird das überhaupt unterstützt oder muss ich komplett auf wechseln? JWTAuthenticator? Brauche ich darüber hinaus separate Aktionen, obwohl bis auf den Authentifikator alles dieselbe Implementierung sein sollte?


5
2018-02-13 17:11


Ursprung


Antworten:


Ja, Silhouette ermöglicht es Ihnen, mehrere zu implementieren Authentifikatoren. So können Sie das implementieren JWTAuthenticator das bietet seinen JWT Authenticator Service zusammen mit Ihrem CookieAuthenticator:

  1. Wie Douglas Liu, bereits in dem Kommentar hingewiesen, müssen Sie ein zusätzliches erstellen Umgebung Art. Es sollte ein verbinden Identity mit dem jeweiligen Authenticator.

Beispielsweise:

trait CookieEnv extends Env {
  type I = Account
  type A = CookieAuthenticator
}

trait JWTEnv extends Env {
  type I = Account
  type A = JWTAuthenticator
}
  1. Implementieren Sie die JWT-Bindungen in Ihrem Silhouette-Modul. Bitte werfen Sie einen Blick auf Spiel-Silhouette-Winkel-Samen für ein vollständiges Beispiel.

Zum Beispiel:

class SilhouetteModule extends AbstractModule with ScalaModule {

  def configure() {
    bind[Silhouette[CookieEnv]].to[SilhouetteProvider[CookieEnv]]
    bind[Silhouette[JWTEnv]].to[SilhouetteProvider[JWTEnv]]
    // ...
    ()
  }

   @Provides
  def provideCookieEnvironment(
                                userService: AccountService,
                                authenticatorService: AuthenticatorService[CookieAuthenticator],
                                eventBus: EventBus): Environment[CookieEnv] = {

    Environment[CookieEnv](
      userService,
      authenticatorService,
      Seq(),
      eventBus
    )
  }

  @Provides
  def provideJWTEnvironment(
                             userService: AccountService,
                             authenticatorService: AuthenticatorService[JWTAuthenticator],
                             eventBus: EventBus): Environment[JWTEnv] = {

    Environment[JWTEnv](
      userService,
      authenticatorService,
      Seq(),
      eventBus
    )
  }

// ...

  @Provides
  def provideCookieAuthenticatorService(
                                         @Named("authenticator-cookie-signer") cookieSigner: CookieSigner,
                                         @Named("authenticator-crypter") crypter: Crypter,
                                         fingerprintGenerator: FingerprintGenerator,
                                         idGenerator: IDGenerator,
                                         configuration: Configuration,
                                         clock: Clock): AuthenticatorService[CookieAuthenticator] = {

    val config = configuration.underlying.as[CookieAuthenticatorSettings]("silhouette.authenticator")
    val encoder = new CrypterAuthenticatorEncoder(crypter)

    new CookieAuthenticatorService(config, None, cookieSigner, encoder, fingerprintGenerator, idGenerator, clock)
  }

  @Provides
  def provideJWTAuthenticatorService(
                                      @Named("authenticator-crypter") crypter: Crypter,
                                      idGenerator: IDGenerator,
                                      configuration: Configuration,
                                      clock: Clock): AuthenticatorService[JWTAuthenticator] = {

    val config = configuration.underlying.as[JWTAuthenticatorSettings]("silhouette.authenticator")
    val encoder = new CrypterAuthenticatorEncoder(crypter)

    new JWTAuthenticatorService(config, None, encoder, idGenerator, clock)
  }

// ...

}
  1. Ergänzen Sie die JWTAuthenticator  Konfigurationseinstellungen zu deinem silhouette.conf:

Beispielsweise:

authenticator.fieldName = "X-Auth-Token"
authenticator.requestParts = ["headers"]
authenticator.issuerClaim = "Your fancy app"
authenticator.authenticatorExpiry = 12 hours
authenticator.sharedSecret = "!!!changeme!!!"
  1. Erstellen Sie eine separate Route für die Authentifizierung über JWT:

Zum Beispiel in deinem app.routes Datei, füge die folgende Zeile hinzu:

# JWT Authentication
POST        /api/jwt/authenticate        controllers.auth.api.AuthController.authenticate
  1. Endlich in deinem AuthController, füge das entsprechende hinzu authenticate Methode.

Beispielcode (angepasst von SignInController.scala):

implicit val dataReads = (
  (__ \ 'email).read[String] and
    (__ \ 'password).read[String] and
    (__ \ 'rememberMe).read[Boolean]
  ) (SignInForm.SignInData.apply _)

def authenticate = Action.async(parse.json) { implicit request =>
  request.body.validate[SignInForm.SignInData].map { signInData =>
    credentialsProvider.authenticate(Credentials(signInData.email, signInData.password)).flatMap { loginInfo =>
      accountService.retrieve(loginInfo).flatMap {
        case Some(user) => silhouette.env.authenticatorService.create(loginInfo).map {
          case authenticator if signInData.rememberMe =>
            val c = configuration.underlying
            authenticator.copy(
              expirationDateTime = clock.now + c.as[FiniteDuration]("silhouette.authenticator.rememberMe.authenticatorExpiry"),
              idleTimeout = c.getAs[FiniteDuration]("silhouette.authenticator.rememberMe.authenticatorIdleTimeout")
            )
          case authenticator => authenticator
        }.flatMap { authenticator =>
          Logger.info(s"User ${user._id} successfully authenticated.")
          silhouette.env.eventBus.publish(LoginEvent(user, request))
          silhouette.env.authenticatorService.init(authenticator).map { token =>
            Ok(Json.obj("token" -> token))
          }
        }
        case None => Future.failed(new IdentityNotFoundException("Couldn't find user."))
      }
    }.recover {
      /* Login did not succeed, because user provided invalid credentials. */
      case e: ProviderException =>
        Logger.info(s"Host ${request.remoteAddress} tried to login with invalid credentials (email: ${signInData.email}).")
        Unauthorized(Json.obj("error" -> Messages("error.invalidCredentials")))
    }
  }.recoverTotal {
    case e: JsError =>
      Logger.info(s"Host ${request.remoteAddress} sent invalid auth payload. Error: $e.")
      Future.successful(Unauthorized(Json.obj("error" -> Messages("error.invalidPayload"))))
  }
}

1
2018-03-11 08:43