隨着越來越多的人對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.
問題:
- 沒有SSL保護(這可能是一個改進,還沒有在Scala/Lift中看過這個)。任何來自別人的經驗都可能有用?
- 使用會話變量。也許有更好的方法來保持Scala/Lift的狀態?
- 是否已經有特別是用於登錄/註銷在Lift中我可能錯過了什麼?
- 這不是很長,但可能會更多精簡版? (我不想犧牲太多的可讀性,其他開發人員需要快速理解它)
- 其他建議?
乾杯,
馬克。
你沒有提到它,但你看看在Lift中的ProtoUser/MegaProtoUser代碼嗎? – Debilski 2011-05-23 08:16:41