Поскольку все больше и больше людей интересуются Scala (как и я), а не вопросом, я бы хотел обсудить одну реализацию фрагмента входа / выхода для веб-приложения на основе Lift .
Я только начал изучать Scala и Lift, так что, вероятно, не лучший способ реализовать такую функцию, но я хотел бы поделиться ею с другими новичками и обсудить это с более опытными разработчиками.
Обратите внимание, что я также не эксперт в веб-разработке. Любая помощь для улучшений будет принята с благодарностью (особенно связанные с производительностью и безопасностью); -)
1) Прежде всего, фрагмент должен быть легко подключаемым, например, с 1 строкой кода в шаблоне по умолчанию. Я сделал это, используя встроенную функцию Lift (обратите внимание на подчеркивание, чтобы его нельзя было отобразить как саму страницу, а вызвать только из отрендеренной страницы, короче говоря, какой-то «частный» фрагмент) :
<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) ... и теперь логика 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
}
Комментарии:
- Выбор между двумя формами осуществляется с помощью логики, отображающей предоставленную разметку или NodeSeq.Empty , в зависимости от того, вошел ли пользователь в систему или вышел из нее.
- Я использовал Lift: Msg , чтобы иметь сообщения об ошибках рядом с соответствующими полями (имя / пароль). Сообщение отправляется с использованием S.error в логике и соответствующего идентификатора.
- Я фактически выполняю проверки в помощнике 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, которое я мог пропустить?
- Это не очень долго, но может быть более компактно ? (Хотелось бы не жертвовать слишком большой читабельностью. Другие разработчики должны быстро это понять)
- Любое другое предложение?
Приветствия
Марк.