5 votes

Meilleure façon de créer un formulaire de connexion/déconnexion en Scala utilisant Lift

De plus en plus de personnes s'intéressent à Scala (comme moi), plutôt que de poser une question, j'aimerais discuter d'une implémentation d'un extrait de code de connexion/déconnexion pour une webapp basée sur Lift.

Je viens juste de commencer à apprendre Scala et Lift donc ce n'est probablement pas la meilleure façon d'implémenter une telle fonctionnalité mais j'aimerais la partager pour d'autres débutants et en discuter avec des développeurs plus expérimentés. Veuillez noter que je ne suis pas non plus un expert en développement web. Toute aide pour les améliorations serait grandement appréciée (surtout celles liées aux performances et à la sécurité) ;-)

1) Tout d'abord, l'extrait doit pouvoir être facilement plugable, avec 1 seule ligne de code dans votre modèle par défaut. Je l'ai fait en utilisant la fonctionnalité embedded de Lift (remarquez le trait bas pour qu'il ne puisse pas être rendu en tant que page en lui-même mais seulement invoqué à partir d'une page rendue, en bref, une sorte d'extrait "privé"):

2) Ensuite, dans _logInForm.html, j'utilise le balisage ci-dessous et un affichage conditionnel pour gérer tout :

            Nom d'utilisateur :  
            Mot de passe :  

        Connecté en tant que .

3) ... et maintenant la logique Scala/Lift derrière ce balisage :

object LogInForm {
  private object name extends SessionVar("")
  private object password extends RequestVar("")
  private object referer extends RequestVar(S.referer openOr "/")
  var isLoggedIn = false

  def loggedIn(html: NodeSeq) =
    if (isLoggedIn) html else NodeSeq.Empty

  def loggedOut(html: NodeSeq) =
    if (!isLoggedIn) html else NodeSeq.Empty

  def logIn = {
    def processLogIn() {
      Validator.isValidName(name) match {
        case true => {
          Validator.isValidLogin(name, password) match {
            case true => { isLoggedIn = true } // Succès : connecté
            case _ => S.error("password", "Nom d'utilisateur/mot de passe invalide !")
          }
        }
        case _ => S.error("name", "Format de nom d'utilisateur invalide !")
      }
    }

    val r = referer.is
    "name=name" #> SHtml.textElem(name) &
      "name=password" #> (
        SHtml.textElem(password) ++
          SHtml.hidden(() => referer.set(r))) &
      "type=submit" #> SHtml.onSubmitUnit(processLogIn)
  }

  def logOut = {
    def processLogOut() { isLoggedIn = false }
    val r = referer.is
    "type=submit" #> SHtml.onSubmitUnit(processLogOut)
  }

  def getName = "*" #> name.is
}

Commentaires :

  • La sélection entre les deux formulaires est faite par la logique, rendant soit le balisage fourni, soit NodeSeq.Empty, en fonction du fait que l'utilisateur soit connecté ou déconnecté.
  • J'ai utilisé Lift:Msg pour avoir des messages d'erreur à côté des champs appropriés (nom/mot de passe). Le message est envoyé en utilisant S.error dans la logique derrière et l'id approprié.
  • J'effectue en fait les vérifications dans un assistant Validator en utilisant des expressions régulières et des vérifications de formats, etc. Cela renvoie un booléen à chaque fois, donc le pattern matching est trivial.
  • J'utilise le referer pour que l'utilisateur puisse se connecter / se déconnecter tout en restant sur la même page.
  • Le nom d'utilisateur est conservé en tant que variable de session et affiché lorsqu'il est connecté.

4) Vous pouvez contrôler l'accès à d'autres pages en faisant ce qui suit dans Boot.scala :

    def sitemap() = SiteMap(
      Menu("Accueil") / "index",
      Menu("Page protégée") / "nomDeLaPageProtégée" >> If(() => LogInForm.isLoggedIn, ""),
      // etc.

Questions :

  1. Aucune protection SSL (cela pourrait être une amélioration, je n'ai pas encore regardé cela en Scala/Lift). Toute expérience d'une autre personne pourrait être utile ?
  2. Utilisation de variable de session. Peut-être qu'il y a une meilleure façon de conserver l'état en Scala/Lift ?
  3. Y a-t-il déjà quelque chose spécialement conçu pour se connecter/déconnecter dans Lift que j'aurais pu manquer ?
  4. Il n'est pas très long, mais pourrait peut-être être plus compact ? (J'aimerais ne pas sacrifier trop de lisibilité cependant. Les autres développeurs doivent le comprendre rapidement)
  5. Toute autre suggestion ?

À bientôt,

Marc.

2voto

thoredge Points 5829
  1. Cela montre comment forcer l'utilisation de SSL, vous utiliserez généralement cela pour le menu de la page du formulaire de connexion: Filtre Lift pour forcer SSL
  2. Une variable de session est généralement la meilleure façon de conserver des informations de session
  3. ProtoUser (vous pouvez utiliser Lifty (http://lifty.github.com/) pour configurer un projet avec une connexion comme exemple)

2voto

rfreytag Points 624

Lift fournit un cadre de structure pour ces cas d'utilisation. Vous voulez jeter un œil au code source de net.liftweb.proto.ProtoUser. Surtout login() et loginXhtml.

Les exemples de base de Lift font comme suit:

  1. Créez votre propre classe utilisateur mappée qui utilise tout le code lift désagréable

    package votresociete.model
    
    import net.liftweb.mapper._
    import net.liftweb.util._
    import net.liftweb.common._
    
    class User extends MegaProtoUser[User] { 
      // votre code, principalement des remplacements
    
    }
    
    object User extends User with MetaMegaProtoUser[User] {
      override def dbTableName = "users"
      // autre code lié à la base de données
    }
  2. Dans votre Boot après avoir défini votre plan de site, faites ce qui suit:

    // n'oubliez pas d'importer votre utilisateur
    def sitemap() = Sitemap(Menu("Accueil") / "index" >> User.AddUserMenusAfter)
    
    // maintenant vient la magie
    LiftRules.setSiteMap(User.sitemapMutator(sitemap()))

Cela inclura de nombreux liens sur votre page, tous regroupés sous /user_mgt par exemple sign_up, login, lost_password. Pour moi, c'est une excellente base à partir de laquelle travailler. Vous pouvez remplacer presque tout ce qui se passe dans ProtoUser, ou simplement copier les bons morceaux et implémenter tout vous-même.

Aussi, si quelqu'un a des documents supplémentaires à ce sujet, ce serait très utile. Pour le moment, j'essaie de comprendre la plupart des choses en utilisant les sources.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X