使用Lift在Scala中创建登录/注销表单的最佳方法 [英] Best way to create a login/logout form in Scala using Lift

查看:62
本文介绍了使用Lift在Scala中创建登录/注销表单的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

随着越来越多的人(像我自己)对Scala感兴趣,而不是提出一个问题,我想讨论基于Lift的Web应用的登录/注销代码段的一种实现方式.

As more and more people are interested in Scala (like myself), rather than a question, I'd like to discuss one implementation of a login/logout snippet for a webapp based on Lift.

我刚刚开始学习Scala和Lift,所以不是实现此功能的最佳方法,但我想与其他初学者分享并与经验丰富的开发人员讨论. 请注意,我也不是Web开发方面的专家.任何改进方面的帮助(特别是与性能和安全性相关的帮助)将不胜感激;-)

I just started to learn Scala and Lift so it's probably not the best way to implement such a feature but I'd like to share it for other beginners and discuss it with more experienced developers. Please note that I'm also not an expert in web development. Any help for improvements would be greatly appreciated (especially performance and security related ones) ;-)

1)首先,代码段需要易于插入,例如默认模板中只有1行代码.我已经使用嵌入式提升功能(注意下划线,因此不能将其呈现为页面本身,而只能从呈现的页面中调用,简而言之,是某种私有"代码段)来完成此操作):

1) First of all, the snippet needs to be easily plugable, like with 1 line of code in your default template. I've done it using the embedded Lift feature (notice the underscore so it can't be rendered as a page itself but only invoked from a rendered page, in short, some kind of "private" snippet):

<lift:embed what="_logInForm" />

2)然后,在_logInForm.html中,我使用以下标记和条件显示来处理所有问题:

2) Then, in _logInForm.html, I use the below markup and a conditional display to handle everything:

<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逻辑:

3) ... and now the Scala/Lift logic behind this markup:

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 (其背后的逻辑和适当的ID)发送的.
  • 我实际上是使用正则表达式和格式检查等在Validator帮助器中执行检查的.每次模式匹配时,这都会返回一个布尔值.
  • 我使用引荐来源网址,因此用户可以在停留在同一页面上的同时登录/注销.
  • 用户名保留为会话变量,并在登录时显示.
  • The selection between the two forms is made by the logic, rendering either the provided markup or NodeSeq.Empty, based on the fact the user is either logged in or logged out.
  • I used Lift:Msg to have error messages next to the appropriate fields (name/password). The message is sent using S.error in the logic behind and the appropriate id.
  • I actually perform the checks in a Validator helper using regexps and formats checks, etc. This return a boolean each time to pattern matching is trivial.
  • I use the referer so the user can log in / log out while staying on the same page.
  • The username is kept as a session variable and shown when logged in.

4)您可以在Boot.scala中执行以下操作来控制对其他页面的访问:

4) You can control access to other pages doing the following in 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. 还有其他建议吗?
  1. No SSL protection (that could be an improvement, haven't had a look at this in Scala/Lift yet). Any experience from someone else could be useful?
  2. Use of session variable. Maybe there is a better way to keep state in Scala/Lift?
  3. Is there already something made especially for logging in/out in Lift that I could have missed?
  4. It's not very long, but could maybe be more compact? (I'd like not to sacrifice too much readability though. Other developers need to quickly understand it)
  5. Any other suggestion?

干杯

马克.

推荐答案

Lift为这些用例提供了一个脚手架框架.您想看一下net.liftweb.proto.ProtoUser的源代码.尤其是login()loginXhtml.

Lift provides a scaffolding framework for these usecases. You want to have a look at the source code of net.liftweb.proto.ProtoUser. Especially login() and loginXhtml.

Lift的基本示例通过以下方式进行操作:

The basic examples of Lift do it the following way:

  1. 创建一个使用所有讨厌的提升代码的自己的映射用户类

  1. Create an own mapped user class that uses all the nasty lift code

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
}

  • 在定义站点地图后的启动中,执行以下操作:

  • In your Boot after you defined your sitemap, do the following:

    // 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中几乎发生的所有事情,或者只是复制漂亮的片段并自己实现所有功能.

    This will include many links on your page, all gathered under /user_mgt e.g. sign_up, login, lost_password. For me this is a great base to work from. You can override almost all the things that happen in ProtoUser, or just copy the nice bits and implement everything yourself.

    如果有人对此有其他文档,这将非常有帮助.目前,我尝试使用来源了解大部分内容.

    Also if someone has additional docs on that, it will be very helpful. At the moment I try to figure out the most part using the sources.

    这篇关于使用Lift在Scala中创建登录/注销表单的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆