GoodSoft
  • Projekte
  • Unser Team
  • Kunden
  • Technologien
  • Karriere
  • Blog
  • Kontakt
  • Hub of Talents
  • Deutsch
    • Polski
    • English
    • Deutsch
Seite wählen

Play Silhouette und Social Logins

von GoodSoft | Aug. 5, 2022 | Uncategorized | 0 Kommentare

Google Facebook Linkedin login implementation programming play silhouette

Play Silhouette und Social logins

Die meisten Benutzer können sich nicht die Mühe machen, ein Formular mit ihrer E-Mail, ihrem vollständigen Namen, demselben Login wie auf jeder anderen Website und (dem schwierigsten Teil) zwei identischen, komplizierten und starken Passwörtern auszufüllen. Dann müssen sie sich jedes Mal, wenn sie auf Ihre Website zurückkehren, erneut anmelden, was bedeutet, dass sie sich daran erinnern müssen, welches Passwort sie benutzt haben. Eine Möglichkeit, dies zu vereinfachen, ist die Autorisierung von Nutzern für Ihre App mit Hilfe von Social Logins.

Play und Silhouette

Silhouette ist eine beliebte Scala-Authentifizierungsbibliothek für das Play Framework. Sie unterstützt mehrere Authentifizierungsmethoden – einschließlich OAuth2. Sie enthält außerdem mehrere vorkonfigurierte Provider-Klassen für beliebte soziale Websites, was den Arbeitsaufwand minimiert.

Konfiguration

Als Erstes müssen wir den Anbieter der state parameter konfigurieren. Wir werden ihn verwenden, um CSRF-Angriffe zu verhindern.

Der erste Schritt ist das Hinzufügen einiger Konfigurationsschlüssel und -werte zu silhouette.conf. Unser Schnipsel unten zeigt die Konfiguration sowohl für den CSRF-State-Handler als auch für den OAuth2-State-Provider – da wir beide benötigen werden.

# OAuth2 state provider settings
oauth2StateProvider.cookieName="OAuth2TokenSecret"
oauth2StateProvider.cookiePath="/"
oauth2StateProvider.secureCookie=false
oauth2StateProvider.httpOnlyCookie=true
oauth2StateProvider.sameSite="Lax"
oauth2StateProvider.expirationTime=5 minutes
oauth2StateProvider.signer.key = "[changeme]"
oauth2StateProvider.crypter.key = "[changeme]"

# Social state handler
socialStateHandler.signer.key = "[changeme]"

# CSRF state item handler settings
csrfStateItemHandler.cookieName="OAuth2State"
csrfStateItemHandler.cookiePath="/"
csrfStateItemHandler.secureCookie=false
csrfStateItemHandler.httpOnlyCookie=true
csrfStateItemHandler.sameSite="Lax"
csrfStateItemHandler.expirationTime=5 minutes

csrfStateItemHandler.signer.key = "[changeme]"

Signers

Als Nächstes müssenSignerfür den CSRF State Item Handler und den OAuth2 State Provider erstellt werden. Sie werden verwendet, um clientseitige Cookies zu signieren. Diese Implementierung sollte wie die untenstehende aussehen und in der gleichen Datei wie der Rest der Silhouette-Funktionen platziert werden, z. B. SilhouetteModule.scala.

/**
 * Provides the signer for the social state handler.
 *
 * @param configuration The Play configuration.
 * @return The signer for the social state handler.
 */
@Provides @Named("social-state-signer")
def provideSocialStateSigner(configuration: Configuration): Signer = {
 val config = configuration.underlying.as[JcaSignerSettings]("silhouette.socialStateHandler.signer")

 new JcaSigner(config)
}
/**
 * Provides the signer for the CSRF state item handler.
 *
 * @param configuration The Play configuration.
 * @return The signer for the CSRF state item handler.
 */
@Provides @Named("csrf-state-item-signer")
def provideCSRFStateItemSigner(configuration: Configuration): Signer = {
 val config = configuration.underlying.as[JcaSignerSettings]("silhouette.csrfStateItemHandler.signer")

 new JcaSigner(config)
}

Anbieter

Nachdem wir Signererstellt haben, können wir sowohl einen CSRF State Item Handler als auch einen Social State Handler erstellen. Zunächst erstellen wir einen CSRF-Item-Handler.

/**
 * Provides the CSRF state item handler.
 *
 * @param idGenerator The ID generator implementation.
 * @param signer The signer implementation.
 * @param configuration The Play configuration.
 * @return The CSRF state item implementation.
 */
@Provides
def provideCsrfStateItemHandler(
 idGenerator: IDGenerator,
 @Named("csrf-state-item-signer") signer: Signer,
 configuration: Configuration): CsrfStateItemHandler = {
 val settings = configuration.underlying.as[CsrfStateSettings]("silhouette.csrfStateItemHandler")
 new CsrfStateItemHandler(settings, idGenerator, signer)
}

Mit diesem CSRF-State-Item-Handler werden wir nun den Social-State-Handler erstellen. Wir werden DefaultSocialStateHandler verwenden, da die Silhouette-Dokumentation nahelegt, dass dies die beste Option ist.

/**
 * Provides the social state handler.
 *
 * @param signer The signer implementation.
 * @return The social state handler implementation.
 */
@Provides
def provideSocialStateHandler(
 @Named("social-state-signer") signer: Signer,
 csrfStateItemHandler: CsrfStateItemHandler): SocialStateHandler = {

 new DefaultSocialStateHandler(Set(csrfStateItemHandler), signer)
}

Anbieter sozialer Medien

Nachdem wir nun Silhouette für den OAuth2-Workflow konfiguriert und gegen CSRF-Angriffe gesichert haben, können wir unsere Anbieter für soziale Websites erstellen. Für die Zwecke dieses Artikels werden wir nur den Google-Anbieter implementieren, aber andere Konfigurationen sind sehr ähnlich. Sie können Beispielkonfigurationen in der Silhouette-Dokumentation finden. Höchstwahrscheinlich werden Sie mehr als einen Anbieter für den Komfort Ihrer Benutzer verwenden wollen. Der in diesem Teil des Artikels vorgestellte Code ist leicht erweiterbar.

Anbieter-Konfiguration

Als Erstes müssen Sie die Konfiguration des Anbieters in die Datei silhouette.conf aufnehmen. Für Google sollte sie ähnlich wie die folgende aussehen.

google {
     authorizationURL="https://accounts.google.com/o/oauth2/auth"
     accessTokenURL="https://accounts.google.com/o/oauth2/token"
     redirectURL=YOUR_APP_DOMAIN/authenticate/google"
     clientID="some_client_id"
     clientSecret="some_client_secret"
     scope="profile email"
   }

Hinweis: Sie müssen clientID und clientSecret in Ihrem Google-Konto erstellen.

Der nächste Schritt besteht darin, einen GoogleProvider. zu erstellen. Auch hier werden wir dies in der Klasse SilhouetteModuletun. Das folgende Codeschnipsel zeigt eine Implementierung, die die in silhouette.confgespeicherte Konfiguration verwendet.

/**
 * Provides the Google provider.
 *
 * @param httpLayer The HTTP layer implementation.
 * @param socialStateHandler The social state handler implementation.
 * @param configuration The Play configuration.
 * @return The Google provider.
 */
@Provides
def provideGoogleProvider(
 httpLayer: HTTPLayer,
 socialStateHandler: SocialStateHandler,
 configuration: Configuration): GoogleProvider = {

 new GoogleProvider(httpLayer, socialStateHandler, configuration.underlying.as[OAuth2Settings]("silhouette.google"))
}

Jetzt könnten wir nur diesen Anbieter für die weitere Implementierung verwenden, aber um die Erweiterbarkeit zu erleichtern, werden wir SocialProviderRegistry erstellen. So können wir in Zukunft leicht weitere Anbieter hinzufügen, ohne dass wir die Implementierung anderer Klassen ändern müssen. Wir können diese Registry wie folgt erstellen:

/**
 * Provides the social provider registry.
 *
 * @param facebookProvider The Facebook provider implementation.
 * @param googleProvider The Google provider implementation.
 * @param linkedInProvider The LinkedIn provider implementation.
 * @return The Silhouette environment.
 */
@Provides
def provideSocialProviderRegistry(
 googleProvider: GoogleProvider
 // add more providers here
 ): SocialProviderRegistry = {

 SocialProviderRegistry(Seq(
   googleProvider
   // add more providers here
 )) }

Authentifizierungs-Controller

Nachdem wir nun Anbieter erstellt haben, müssen wir einen Endpunkt für die Authentifizierung erstellen. Um auf unser Repository zuzugreifen, müssen wir es zunächst in den Controller injizieren, indem wir @Inject()(socialProviderRegistry: SocialProviderRegistry) zur Controllerklasse hinzufügen. Der nächste Schritt besteht darin, eineAction zu erstellen, mit der sich der Benutzer auf der Grundlage der vom Anbieter gesendeten Daten anmeldet. Die folgende Methode verwendet den provider String, um festzustellen, welcher soziale Anbieter von unserem Benutzer verwendet wurde, und verwendet den richtigen. Anschließend wird versucht, den Benutzer anhand des zuvor ermittelten Anbieters zu authentifizieren. Als Nächstes wird versucht, den Benutzer mit Hilfe des zuvor bestimmten Anbieters zu authentifizieren. Wenn dies erfolgreich ist (richtig), werden die vom sozialen Anbieter gesendeten Profildaten abgerufen und in der Datenbank gespeichert (userService.save(profile) ist eine benutzerdefinierte Funktion, die Sie selbst erstellen müssen). Wenn der Dienst Some(user) zurückgibt, was in unserer Implementierung bedeutet, dass die Daten korrekt gespeichert wurden, wird ein Authenticator erstellt und ein LoginEvent veröffentlicht, mit dem ein neuer Benutzer angemeldet wird.

/**
 * Social log in
 *
 * @param provider login provider
 */
def socialAuthenticate(provider: String) = silhouette.UnsecuredAction.async { implicit request =>
 (socialProviderRegistry.get[SocialProvider](provider) match {

   case Some(p: SocialProvider with CommonSocialProfileBuilder) =>
     p.authenticate().flatMap {

       case Left(result) => Future.successful(result) // Return authentication result with error

       case Right(authInfo) => (for {
         profile <- p.retrieveProfile(authInfo)
         optionalUser <- userService.save(profile)        } yield optionalUser match {          case Some(user) =>
           for {
             authenticator <- silhouette.env.authenticatorService.create(user.loginInfo)
             value <- silhouette.env.authenticatorService.init(authenticator)
             result <- silhouette.env.authenticatorService.embed(value, Redirect(routes.HomeController.index()))            } yield {              silhouette.env.eventBus.publish(LoginEvent(user, request))              result            }          case None => // Error handling while saving user
           Future.successful(Redirect(routes.AuthController.login).flashing("warning" -> Messages("auth.social.alreadyRegistered")))

       }).flatten

     }

   case _ => Future.failed(new ProviderException(s"Cannot authenticate with unexpected social provider $provider")) // Wrong provider key

 }).recover { // Any other unforeseen error handling
   case e: ProviderException =>
     logger.error("Unexpected provider error", e)
     Redirect(routes.AuthController.login).flashing("warning" -> Messages("auth.social.couldNotAuthenticate"))
 }
}

Wie bei jedem Endpunkt müssen wir ihn zur routes Konfiguration hinzufügen. Sie sollte in etwa so aussehen:

GET   /authenticate/:provider  controllers.AuthController.socialAuthenticate(provider: String)

Vorlage

Ein letzter Punkt, der noch erledigt werden muss, ist, den Benutzern den Zugang zu dieser Anmeldemethode zu ermöglichen. Dazu fügen wir dieses Snippet in die Anmeldungsvorlage ein.

@if(socialProviders.providers.nonEmpty) {
  <div class="social-providers mt-2">
     <p class="col-sm-12 justify-content-center d-flex">@messages("auth.signIn.useSocial")</p>
     <div class="col-sm-12 justify-content-center d-flex">
        @for(p <- socialProviders.providers) {       
           <a href="@controllers.routes.AuthController.socialAuthenticate(p.id)" class="social-auth provider @p.id" title="@messages(p.id)"><i aria-hidden="true" class="fab fa-@{p.id} font-50 m-2"></i></a>
        }
     </div>
  </div>
}

Damit werden Links zu allen sozialen Anbietern aus unserem Repository erstellt. class="fab fa-@{p.id} font-50 m-2" holt Anbieter-Icons von FontAwesome.

Poland, Białystok ul. Żurawia 71

+48 512 098 660

contact@goodsoft.pl

  • Folgen
  • Folgen

Project covered

GoodSoft company is implementing a project co-financed by the European Funds from the Operational Programme Eastern Poland Priority axis 1 Entrepreneurial Eastern Poland measure 1.2 Internationalization of SMEs entitled “ Internationalization as an opportunity for the development of GoodSoft Michał Jurczuk company“, project number POPW .01.02.00-20-0026/20

Privacy policy

This website uses cookies for profiling purposes. Please read our cookie policy and agree to the actions taken. I accept cookies.

See more

Projects
Our Team
Clients
Technologies
Careers
Blog
Contact

Goodsoft | ul. Żurawia 71, 15-540 Białystok, Polska | NIP: 603 002 63 26 | Regon: 200 66 70 57