Лучший способ создать форму входа / выхода в Scala с помощью Lift - PullRequest
5 голосов
/ 23 мая 2011

Поскольку все больше и больше людей интересуются Scala (как и я), а не вопросом, я бы хотел обсудить одну реализацию фрагмента входа / выхода для веб-приложения на основе Lift .

Я только начал изучать Scala и Lift, так что, вероятно, не лучший способ реализовать такую ​​функцию, но я хотел бы поделиться ею с другими новичками и обсудить это с более опытными разработчиками. Обратите внимание, что я также не эксперт в веб-разработке. Любая помощь для улучшений будет принята с благодарностью (особенно связанные с производительностью и безопасностью); -)

1) Прежде всего, фрагмент должен быть легко подключаемым, например, с 1 строкой кода в шаблоне по умолчанию. Я сделал это, используя встроенную функцию Lift (обратите внимание на подчеркивание, чтобы его нельзя было отобразить как саму страницу, а вызвать только из отрендеренной страницы, короче говоря, какой-то «частный» фрагмент) :

<lift:embed what="_logInForm" />

2) Затем в _logInForm.html я использую приведенную ниже разметку и условное отображение для обработки всего:

<div>
    <!-- User is not logged in, show a form to log in using the method loggedOut -->
    <lift:LogInForm.loggedOut>
        <form class="lift:LogInForm.logIn?form=post">
            <label for="textName">Username: </label><input type="text" id="textName" name="name" /> <span class="lift:Msg?id=name;errorClass=error"/><br/>
            <label for="textPassword">Password: </label><input type="password" id="textPassword" name="password" /> <span class="lift:Msg?id=password;errorClass=error"/><br/>
            <input type="submit" value="Log in" />
        </form>
    </lift:LogInForm.loggedOut>

    <!-- User is logged in, show who she is and a way to log out using the method loggedIn -->
    <lift:LogInForm.loggedIn>
        <form class="lift:LogInForm.logOut?form=post">
        Connected as <span class="lift:LogInForm.getName" />.<br />
        <input type="submit" id="btnLogOut" value="Log out" />
        </form>
    </lift:LogInForm.loggedIn>
</div>

3) ... и теперь логика Scala / Lift за этой разметкой:

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 } // Success: logged in
            case _ => S.error("password", "Invalid username/password!")
          }
        }
        case _ => S.error("name", "Invalid username format!")
      }
    }

    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
}

Комментарии:

  • Выбор между двумя формами осуществляется с помощью логики, отображающей предоставленную разметку или NodeSeq.Empty , в зависимости от того, вошел ли пользователь в систему или вышел из нее.
  • Я использовал Lift: Msg , чтобы иметь сообщения об ошибках рядом с соответствующими полями (имя / пароль). Сообщение отправляется с использованием S.error в логике и соответствующего идентификатора.
  • Я фактически выполняю проверки в помощнике Validator, используя регулярные выражения и проверки форматов и т. Д. Это возвращает логическое значение каждый раз, когда сопоставление с образцом тривиально.
  • Я использую referer , чтобы пользователь мог входить / выходить из системы, оставаясь на той же странице.
  • Имя пользователя сохраняется как переменная сеанса и отображается при входе в систему.

4) Вы можете контролировать доступ к другим страницам, выполняя следующие действия в Boot.scala:

    def sitemap() = SiteMap(
      Menu("Home") / "index",
      Menu("Protected page") / "protectedPageName" >> If(() => LogInForm.isLoggedIn, ""),
      // etc.

Вопросы:

  1. Нет защиты SSL (что может быть улучшением, но я еще не видел этого в Scala / Lift). Может быть полезен опыт кого-то еще?
  2. Использование переменной сеанса . Может быть, есть лучший способ сохранить состояние в Scala / Lift?
  3. Уже есть что-то сделанное специально для входа / выхода в Lift, которое я мог пропустить?
  4. Это не очень долго, но может быть более компактно ? (Хотелось бы не жертвовать слишком большой читабельностью. Другие разработчики должны быстро это понять)
  5. Любое другое предложение?

Приветствия

Марк.

Ответы [ 2 ]

2 голосов
/ 07 июня 2013

Lift предоставляет каркас лесов для этих случаев использования. Вы хотите взглянуть на исходный код net.liftweb.proto.ProtoUser. Особенно login() и loginXhtml.

Основные примеры Lift делают это следующим образом:

  1. Создайте собственный сопоставленный пользовательский класс, который использует весь неприятный код лифта

    package yourcompany.model
    
    import net.liftweb.mapper._
    import net.liftweb.util._
    import net.liftweb.common._
    
    class User extends MegaProtoUser[User] { 
      // your code, mostly overrides
    
    }
    
    object User extends User with MetaMegaProtoUser[User] {
      override def dbTableName = "users"
      // other database related code
    }
    
  2. В вашем Boot после того, как вы определили свою карту сайта, сделайте следующее:

    // do not forget to import your user
    def sitemap() = Sitemap(Menu("Home") / "index" >> User.AddUserMenusAfter)
    
    // now comes the magic
    LiftRules.setSiteMap(User.sitemapMutator(sitemap()))
    

Это будет включать в себя множество ссылок на вашей странице, все собраны в /user_mgt например. sign_up, login, lost_password. Для меня это отличная база для работы. Вы можете переопределить почти все, что происходит в ProtoUser, или просто скопировать интересные фрагменты и реализовать все самостоятельно.

Также, если у кого-то есть дополнительные документы по этому вопросу, это будет очень полезно. На данный момент я пытаюсь выяснить большую часть, используя источники.

2 голосов
/ 23 мая 2011
  1. Здесь показано, как принудительно использовать SSL, вы обычно будете использовать его для меню страницы формы входа в систему: Поднять фильтр для принудительного использования ssl
  2. Переменная сеанса обычно является лучшим способом сохранить информацию о сеансе
  3. ProtoUser (вы можете использовать Lifty (http://lifty.github.com/) для настройки проекта с логином в качестве примера)
...