Перейти к основному содержимому

Вход в веб-приложение Spring — обработка ошибок и локализация

· 7 мин. чтения

1. Обзор

В этой статье мы собираемся проиллюстрировать, как реализовать простую страницу входа с помощью Spring MVC для приложения, которое обрабатывает аутентификацию с помощью Spring Security в бэкэнде.

Подробную информацию о том, как обрабатывать вход с помощью Spring Security, можно найти в статье , в которой подробно рассказывается о настройке и реализации этого.

2. Страница входа

Начнем с определения очень простой страницы входа :

<html>
<head></head>
<body>
<h1>Login</h1>
<form name='f' action="login" method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td><input name="submit" type="submit" value="submit" /></td>
</tr>
</table>
</form>
</body>
</html>

Теперь давайте включим проверку на стороне клиента, чтобы убедиться, что имя пользователя и пароль были введены еще до того, как мы отправим форму. В этом примере мы будем использовать обычный Javascript, но JQuery также является отличным вариантом:

<script type="text/javascript">
function validate() {
if (document.f.username.value == "" && document.f.password.value == "") {
alert("Username and password are required");
document.f.username.focus();
return false;
}
if (document.f.username.value == "") {
alert("Username is required");
document.f.username.focus();
return false;
}
if (document.f.password.value == "") {
alert("Password is required");
document.f.password.focus();
return false;
}
}
</script>

Как видите, мы просто проверяем , пусты ли поля имени пользователя или пароля ; если они есть – появится окно сообщения javascript с соответствующим сообщением.

3. Локализация сообщений

Далее — давайте локализуем сообщения, которые мы используем во внешнем интерфейсе. Существуют типы таких сообщений, и каждое локализовано по-своему:

  1. Сообщения, генерируемые перед обработкой формы контроллерами или обработчиками Spring. На эти сообщения можно ссылаться на страницах JSP, и они локализованы с помощью локализации Jsp/Jslt (см. Раздел 4.3.)
  2. Сообщения, которые локализуются после отправки страницы на обработку Spring (после отправки формы входа ); эти сообщения локализованы с помощью локализации Spring MVC (см. Раздел 4.2.)

3.1. Файлы message.properties _

В любом случае нам нужно создать файл message.properties для каждого языка, который мы хотим поддерживать; имена файлов должны соответствовать следующему соглашению: messages_[localeCode].properties .

Например, если мы хотим поддерживать сообщения об ошибках на английском и испанском языках, у нас будет файл: messages_en.properties и messages_es_ES.properties . Обратите внимание, что для английского языка — messages.properties также допустимо.

Мы поместим эти два файла в путь к классам проекта ( src/main/resources ). Файлы просто содержат коды ошибок и сообщения, которые нам нужно отображать на разных языках, например:

message.username=Username required
message.password=Password required
message.unauth=Unauthorized access!!
message.badCredentials=Invalid username or password
message.sessionExpired=Session timed out
message.logoutError=Sorry, error login out
message.logoutSucc=You logged out successfully

3.2. Настройка локализации Spring MVC

Spring MVC предоставляет LocaleResolver , который работает в сочетании с его API LocaleChangeInterceptor , чтобы сделать возможным отображение сообщений на разных языках в зависимости от настройки локали. Чтобы настроить локализацию — нам нужно определить следующие bean-компоненты в нашей конфигурации MVC :

@Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}

@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
return cookieLocaleResolver;
}

По умолчанию преобразователь локали получает код локали из заголовка HTTP. Чтобы принудительно использовать локаль по умолчанию, нам нужно установить ее в localeResolver() :

@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
cookieLocaleResolver.setDefaultLocale(Locale.ENGLISH);
return cookieLocaleResolver;
}

Этот сопоставитель локали является CookieLocaleResolver , что означает, что он сохраняет информацию о локали в файле cookie на стороне клиента; как таковой - он будет помнить локаль пользователя каждый раз, когда он входит в систему и в течение всего посещения.

в качестве альтернативы есть SessionLocaleResolver , который запоминает локаль на протяжении всего сеанса. Чтобы вместо этого использовать этот LocaleResolver , нам нужно заменить вышеуказанный метод следующим:

@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
return sessionLocaleResolver;
}

Наконец, обратите внимание, что LocaleChangeInterceptor изменит локаль на основе значения параметра lang , отправленного со страницей входа по простым ссылкам:

<a href="?lang=en">English</a> |
<a href="?lang=es_ES">Spanish</a>

3.3. Локализация JSP/JSLT

JSP/JSLT API будет использоваться для отображения локализованных сообщений, перехваченных на самой странице jsp. Чтобы использовать библиотеки локализации jsp, мы должны добавить следующие зависимости в pom.xml :

<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.2-b01</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

4. Отображение сообщений об ошибках

4.1. Ошибки проверки входа

Чтобы использовать поддержку JSP/JSTL и отображать локализованные сообщения в файле login.jsp, давайте реализуем следующие изменения на странице:

1. Добавьте в файл login.jsp следующий элемент библиотеки тегов :

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
  1. Добавьте элемент jsp/jslt, который будет указывать на файлы messages.properties :
<fmt:setBundle basename="messages" />
  1. Добавьте следующие элементы <fmt:…> для хранения сообщений в переменных jsp:
<fmt:message key="message.password" var="noPass" />
<fmt:message key="message.username" var="noUser" />
  1. Измените сценарий проверки входа, который мы видели в разделе 3, чтобы локализовать сообщения об ошибках:
<script type="text/javascript">
function validate() {
if (document.f.username.value == "" && document.f.password.value == "") {
alert("${noUser} and ${noPass}");
document.f.username.focus();
return false;
}
if (document.f.username.value == "") {
alert("${noUser}");
document.f.username.focus();
return false;
}
if (document.f.password.value == "") {
alert("${noPass}");
document.f.password.focus();
return false;
}
}
</script>

4.2. Ошибки перед входом в систему

Иногда странице входа будет передан параметр ошибки, если предыдущая операция не удалась. Например, кнопка отправки регистрационной формы загрузит страницу входа. Если регистрация прошла успешно, то было бы неплохо показать сообщение об успехе в форме входа и сообщение об ошибке, если верно обратное.

В образце формы входа ниже мы реализуем это, перехватывая параметры regSucc и regError и отображая локализованное сообщение на основе их значений.

<c:if test="${param.regSucc == true}">
<div id="status">
<spring:message code="message.regSucc">
</spring:message>
</div>
</c:if>
<c:if test="${param.regError == true}">
<div id="error">
<spring:message code="message.regError">
</spring:message>
</div>
</c:if>

4.3. Ошибки безопасности входа

В случае сбоя процесса входа по какой-либо причине Spring Security выполнит перенаправление на URL-адрес ошибки входа, который мы определили как /login.html?error=true .

Итак, аналогично тому, как мы показывали статус регистрации на странице, нам нужно сделать то же самое в случае проблемы со входом:

<c:if test="${param.error != null}">
<div id="error">
<spring:message code="message.badCredentials">
</spring:message>
</div>
</c:if>

Обратите внимание, что мы используем элемент <spring:message…> . Это означает, что сообщения об ошибках генерируются во время обработки Spring MVC.

Полную страницу входа, включая проверку js и эти дополнительные сообщения о состоянии, можно найти в проекте github .

4.4. Ошибки выхода

В следующем примере код jsp <c:if test=”${not empty SPRING_SECURITY_LAST_EXCEPTION}”> на странице logout.html проверит наличие ошибки в процессе выхода.

Например, если возникает постоянное исключение, когда настраиваемый обработчик выхода пытается сохранить данные пользователя перед перенаправлением на страницу выхода. Хотя эти ошибки случаются редко, мы также должны обрабатывать их как можно аккуратнее.

Давайте посмотрим на полный файл logout.jsp :

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec"
uri="http://www.springframework.org/security/tags"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION}">
<div id="error">
<spring:message code="message.logoutError">
</spring:message>
</div>
</c:if>
<c:if test="${param.logSucc == true}">
<div id="success">
<spring:message code="message.logoutSucc">
</spring:message>
</div>
</c:if>
<html>
<head>
<title>Logged Out</title>
</head>
<body>
<a href="login.html">Login</a>
</body>
</html>

Обратите внимание, что страница выхода также считывает параметр строки запроса logSucc , и если его значение равно true , будет отображаться локализованное сообщение об успехе.

5. Конфигурация безопасности Spring

В этой статье основное внимание уделяется интерфейсу процесса входа в систему, а не серверу, поэтому мы лишь кратко рассмотрим основные моменты настройки безопасности; для полного конфига вы должны прочитать предыдущую статью .

5.1. Перенаправление на URL-адрес ошибки входа

Следующая директива в элементе <form-login…/> направляет поток приложения на URL-адрес, где будет обрабатываться ошибка входа:

authentication-failure-url="/login.html?error=true"

5.2. Перенаправление успешного выхода из системы

<logout 
invalidate-session="false"
logout-success-url="/logout.html?logSucc=true"
delete-cookies="JSESSIONID" />

Атрибут logout-success-url просто перенаправляет на страницу выхода с параметром, который подтверждает, что выход был успешным.

6. Заключение

В этой статье мы продемонстрировали, как реализовать страницу входа для приложения, поддерживаемого Spring Security, — обработка проверки входа, отображение ошибок аутентификации и локализация сообщений.

В следующей статье мы рассмотрим полную реализацию регистрации с целью подготовки к работе полной реализации процесса входа и регистрации.