Como cada vez más gente está interesada en Scala (como yo), en lugar de una pregunta, me gustaría discutir una implementación de un fragmento de inicio de sesión/cierre de sesión para una aplicación web basada en Lift.La mejor manera de crear un formulario de inicio/cierre de sesión en Scala usando Lift
Acabo de empezar a aprender Scala y Lift por lo que probablemente no sea la mejor manera de implementar una característica de este tipo, pero me gustaría compartirlo con otros principiantes y discutirlo con desarrolladores más experimentados. Tenga en cuenta que tampoco soy un experto en desarrollo web. Cualquier ayuda para la mejora sería muy apreciada (especialmente el rendimiento y los relacionados con la seguridad) ;-)
1) En primer lugar, el fragmento tiene que ser fácilmente enchufable, al igual que con 1 línea de código en su defecto modelo. Lo he hecho con el incrustado función de elevación (nótese el guión bajo por lo que no se puede representar como una página en sí, pero sólo invoca desde una página representada, en definitiva, una especie de fragmento de "privado"):
<lift:embed what="_logInForm" />
2) Luego, en _logInForm.html, utilizo el marcado de abajo y una pantalla condicionalpara manejar todo:
<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) ... y ahora el Scala/Lift lógica detrás de t su marcado:
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
}
Comentarios:
- La selección entre las dos formas es hecho por la lógica, haciendo que sea el margen de beneficio proporcionado o NodeSeq.Empty, basado en el hecho de que el usuario es o bien inició sesión o cerró sesión.
- Utilicé Levante: Msg para tener mensajes de error al lado de los campos apropiados (nombre/contraseña). El mensaje se envía usando S.error en la lógica detrás y la identificación apropiada.
- De hecho, realizo las comprobaciones en un Validator helper usando regexps y formatos de verificación, etc. Esto devuelve un valor booleano cada vez que la coincidencia de patrones es trivial.
- Uso el referer para que el usuario pueda iniciar/cerrar sesión mientras se encuentra en la misma página.
- El nombre de usuario se mantiene como una variable sesión y se muestra cuando se inicia sesión en
4) Puede controlar el acceso a otras páginas haciendo lo siguiente en Boot.scala:.
def sitemap() = SiteMap(
Menu("Home")/"index",
Menu("Protected page")/"protectedPageName" >> If(() => LogInForm.isLoggedIn, ""),
// etc.
Preguntas:
- ninguna protección SSL (eso podría ser una mejora, aún no hemos visto esto en Scala/Lift). ¿Alguna experiencia de alguien más podría ser útil?
- Uso de variable de sesión. Tal vez hay una mejor manera de mantener el estado en Scala/Lift?
- ¿Ya hay algo hecho especialmente para ingresar/salir en Lift que podría haber pasado por alto?
- No es muy largo, pero podría ser más compacto? (Me gustaría no sacrificar demasiada legibilidad. Otros desarrolladores deben entenderlo rápidamente)
- ¿Alguna otra sugerencia?
Cheers,
Marc.
No lo menciona pero ¿echó un vistazo al código ProtoUser/MegaProtoUser que está en Lift? – Debilski