Помимо безопасности Apache Shiro , Spring Security является одним из двух наиболее часто используемых компонентов безопасности, используемых в мире Java. Использование Spring Security с Vaadin требует небольшой работы. В этой статье я покажу вам, как вы можете адаптировать свое приложение Vaadin для приятной игры с Spring Security.
Авторы получают Анри Сару из команды Ваадинов, которая дала ему ценную информацию .
Требования: в этой статье предполагается, что вы знакомы с Spring Security, и используются передовые концепции навигатора Vaadin.
Номинальное использование мандата Spring Security для использования подконтекстов в веб-приложении, каждое из которых затем может быть настроено для разных уровней доступа. Например, / public доступен с анонимным доступом, в то время как / private нужны некоторые специальные разрешения. К сожалению, Ваадин не работает таким образом: представления переводятся в фрагменты, а не в подтексты. С этого момента есть два варианта: либо настроить Vaadin для использования подконтекстов, либо встроить Spring Security в наше приложение. Мы будем использовать последний.
- Первым шагом является создание представления формы входа, которое отправляет события входа в систему.
- Корень подписывается на события входа в систему и обрабатывает попытки аутентификации через выделенный обработчик аутентификации.
- Обработчику должны быть переданы логин, пароль и http-запрос. Поскольку Vaadin скрывает последнее в API, мы должны создать специальный сервлет, который сохраняет его в локальном потоке с помощью служебного класса:
public class RequestHolderApplicationServlet extends ApplicationServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestHolder.setRequest(request);
super.service(request, response);
// We remove the request from the thread local, there's no reason to keep it once the work is done
RequestHolder.clean();
}
}
Обработчик входа использует Spring Security API для создания токена имени пользователя / пароля, необходимого для фреймворка. Затем он получает диспетчер аутентификации из контекста Spring и вызывает соответствующий метод, делегируя реальную аутентификацию настроенному бэкэнду . И последнее, но не менее важное: мы устанавливаем данные аутентификации в контексте Spring Security для последующего использования.
public class AuthenticationService {
public void handleAuthentication(String login, String password, HttpServletRequest httpRequest) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(login, password);
token.setDetails(new WebAuthenticationDetails(httpRequest));
ServletContext servletContext = httpRequest.getSession().getServletContext();
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
AuthenticationManager authManager = wac.getBean(AuthenticationManager.class);
Authentication authentication = authManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
Не забудьте также создать и очистить контекст Spring Security. Поскольку мы уже разработали собственный сервлет, мы его обновим.
public class RequestHolderApplicationServlet extends ApplicationServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
RequestHolder.setRequest(request);
super.service(request, response);
RequestHolder.clean();
SecurityContextHolder.clearContext();
}
}
Теперь корень просто должен попытаться / поймать результаты аутентификации и перейти к желаемому представлению, если это успешно. Работа выполнена!
Подождите, что если пользователь узнает об имени представления и введет фрагмент непосредственно в адресную строку своего браузера? Нет входа в систему, нет аутентификации: он / она будет иметь доступ непосредственно к главному представлению, независимо от его / ее учетных данных.
Итак, есть еще один последний шаг: мы должны связать все наши представления в навигатор и позволить последнему управлять навигацией. Кроме того, мы регистрируем его ViewChangeListener, который будет проверять учетные данные перед изменением представления.
public class ViewChangeSecurityChecker implements ViewChangeListener {
@Override
public boolean isViewChangeAllowed(ViewChangeEvent event) {
if (event.getNewView() instanceof LoginView) {
return true;
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication == null ? false : authentication.isAuthenticated();
}
@Override
public void navigatorViewChanged(ViewChangeEvent event) {}
}
Теперь, когда неаутентифицированный пользователь напрямую вводит имя представления как фрагмент, никаких действий не предпринимается. Обратите внимание, что представление входа в систему должно быть доступно в любом случае.
Обратите внимание, что приведенный выше код проверяет только проверенный статус, а не учетные данные. Вы можете легко улучшить это, сделав репозиторий GitHub .