Помимо безопасности 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 .