使用Lift在Scala中创建登录/注销表单的最佳方法

Mar*_*rré 5 forms scala login lift

随着越来越多的人对Scala感兴趣(比如我自己),而不是一个问题,我想讨论一个基于Lift的webapp登录/注销片段的实现.

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

1)首先,代码片段需要很容易插入,就像默认模板中的1行代码一样.我已经使用嵌入式 Lift功能完成了它(注意下划线,因此它不能呈现为页面本身,而只是从呈现的页面调用,简而言之,某种"私有"代码段):

<lift:embed what="_logInForm" />
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

评论:

  • 两个表单之间的选择由逻辑进行,根据用户登录或注销的事实呈现提供的标记或NodeSeq.Empty.
  • 我使用Lift:Msg在相应的字段(名称/密码)旁边有错误消息.使用后面的逻辑中的S.error和相应的id 发送消息.
  • 我实际上使用regexps和格式检查等在Validator助手中执行检查.每次模式匹配都返回一个布尔值是微不足道的.
  • 我使用referer,因此用户可以在停留在同一页面时登录/注销.
  • 用户名保存为会话变量,并在登录时显示.

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

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

问题:

  1. 没有SSL保护(这可能是一种改进,尚未在Scala/Lift中查看过).其他人的经验可能有用吗?
  2. 使用会话变量.也许有更好的方法来保持Scala/Lift中的状态?
  3. 是否已经有一些特别针对 Lift 登录/退出的内容,我可能错过了?
  4. 它不是很长,但可能更紧凑?(我不想牺牲太多的可读性.其他开发人员需要快速理解它)
  5. 还有其他建议吗?

干杯,

渣.

tho*_*dge 2

  1. 这显示了如何强制使用 SSL,您通常会将其用于登录表单页面菜单:Lift filter to Force ssl
  2. 会话变量通常是保存会话信息的最佳方式
  3. ProtoUser(您可以使用Lifty(http://lifty.github.com/)来设置一个登录项目作为示例)