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.
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) 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) 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) ... 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
}
Comments:
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.
Questions:
Cheers,
Marc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With