2011-05-23 81 views
5

隨着越來越多的人對Scala感興趣,而不是一個問題,我想討論一個登錄/註銷片段的實現基於Lift的Web應用程序。使用Lift在Scala中創建登錄/註銷表單的最佳方式

我剛剛開始學習Scala和Lift,因此它可能是而不是實現此功能的最佳方式,但我想分享給其他初學者並與更有經驗的開發人員討論。 請注意,我也不是Web開發專家。爲改善任何幫助,將不勝感激(尤其是性能和安全相關的);-)

1)首先,在片段必須容易插拔式,就像在默認的1行代碼模板。我已經使用嵌入式提升功能(注意下劃線,因此它不能被渲染爲頁面本身,但只能從渲染頁面調用,簡而言之,某種「私人」代碼段):

<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) ...現在斯卡拉/升降機邏輯背後的邏輯他的標記:

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,基於這樣的事實的用戶要麼是登錄或註銷。
  • 我用電梯:消息有適當的字段(名稱/密碼)旁邊的錯誤消息。該消息使用S.error在後面的邏輯和適當的ID中發送。
  • 我實際上使用正則表達式和格式檢查等方式在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. 其他建議?

乾杯,

馬克。

+1

你沒有提到它,但你看看在Lift中的ProtoUser/MegaProtoUser代碼嗎? – Debilski 2011-05-23 08:16:41

回答

2

Lift爲這些用戶提供了一個腳手架框架。你想看看net.liftweb.proto.ProtoUser的源代碼。尤其是login()loginXhtml

電梯的基本的例子做了以下方法:

  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. 在你的引導你定義後自己的映射的用戶類的sitemap,請執行以下操作:

    // 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中發生的所有事情,或者只是複製漂亮的位並自己實現一切。

此外,如果有人有更多的文件,這將是非常有益的。目前我試圖找出使用源代碼的大部分內容。