Hello World

Spring Security Hello World Java Config

В этом материале мы постараемся написать приложение защищенное Spring Security с применением Java Config (подхода на основе использования аннотаций и классов для настройки контекста Spring приложения) вместо XML.

Используемые Технологии

  • Spring 4.0.5 Release
  • Spring Boot 1.0.1
  • Spring Security 3.2.3 Release
  • Maven
  • Tomcat 8
  • Servlet Api 3.1
  • Java 1.8

Это будет очень простое веб приложение, Hello World на базе Spring MVC и Spring Security. Все настройки мы осуществим используя только Java классы, без единой строчки конфигурации в XML.

Начнем с рассмотрения структуры проекта.

Структура Проекта.

Зависимости Maven (из pom.xml)

  javax.servlet javax.servlet-api 3.1.0 provided  javax.servlet.jsp jsp-api 2.2 provided  org.springframework spring-context 4.0.5.RELEASE jar  org.springframework spring-webmvc 4.0.5.RELEASE jar   org.springframework.security spring-security-core 3.2.4.RELEASE  org.springframework.security spring-security-web 3.2.4.RELEASE  org.springframework.security spring-security-config 3.2.4.RELEASE   org.apache.taglibs taglibs-standard-jstlel 1.2.1   

Далее мы рассмотрим настройку контроллерa Spring MVC.

Контроллер ( AppController.java )

package com.elennaro.sshwa.controllers; //Import section ommited. @Controller public class AppController < @RequestMapping(value = , method = ) public ModelAndView welcomePage() < ModelAndView model = new ModelAndView(); model.addObject("title", "Spring Security Tutorial"); model.addObject("message", "Welcome Page !"); model.setViewName("helloworld"); return model; >@RequestMapping(value = "/protected**", method = RequestMethod.GET) public ModelAndView protectedPage() < ModelAndView model = new ModelAndView(); model.addObject("title", "Spring Security 3.2.4 Hello World Tutorial"); model.addObject("message", "This is protected page - Only for Admin Users!"); model.setViewName("protected"); return model; >@RequestMapping(value = "/confidential**", method = RequestMethod.GET) public ModelAndView adminPage() < ModelAndView model = new ModelAndView(); model.addObject("title", "Spring Security 3.2.4 Hello World Tutorial"); model.addObject("message", "This is confidential page - Need Super Admin Role!"); model.setViewName("protected"); return model; >> 
  • /helloword будет иметь публичный доступ, к нему не будет применяться никаких ограничений безопасности.
  • /protected область с ограниченным доступом, только пользователи обладающие ролью администратора (admin) будут иметь доступ к ней.
  • /confidential область с ограниченным доступом, только пользователи обладающие ролью супер администратора будут иметь доступ к ней.
Читайте также:  Тег input, атрибут type

Настраиваем Spring MVC (WebConfig.java)

Необходимо указать фреймворку Spring где находятся компоненты представления, и как их отображать. Так же надо привязать настройки безопасности. Все это можно сделать с помощью Java класса с аннотацией @Configuration (в будущем мы будем называть такие классы конфигурационными).

package com.elennaro.sshwa.config.application; //Import section ommited. @Configuration @EnableWebMvc @ComponentScan(< "com.elennaro.sshwa.config", "com.elennaro.sshwa.controllers" >) //@Import(< AppSecurityConfig.class >) public class WebConfig < @Bean public InternalResourceViewResolver viewResolver() < InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); return viewResolver; >> 
  • Объявляем конфигурационный класс (с помощью аннотации @Configuration ).
  • С помощью аннотации @ComponentScan указываем фреймворку Spring, что компоненты надо искать внутри пакетов com.elennaro.sshwa.config и com.elennaro.sshwa.controllers . Тут специалисты советуют: лучше всегда указывать конкретные пакеты, а не всё сразу с помощью * . То есть мы могли указать все пакеты: com.elennaro.sshwa.* и все бы работало. Но появись у нас в другом месте такой же @ComponentScan мы бы в лучшем случае пересканировали все пакеты дважды, а в худшем наткнулись на пару неприятных ошибок.
  • Указываем что вьюшки будут лежать в директории /WEB-INF/views/
  • Импортируем класс с настройками безопасности, собственно сам конфигуратор Spring Security (с помощью аннотации @Import(< AppSecurityConfig.class >)) . Эта строчка специально закомментирована в коде. Хотелось показать, что класс с настройками безопасности( AppSecurityConfig.java ) отмеченный (как вы увидите ниже) аннотацией @Configuration будет автоматически найден и подключен базовым контекстом апликации Spring фреймворка, потому что путь к пакету содерфащему класс AppSecurityConfig указан в аннотации @ComponentScan . Благодаря этому Spring найдет и подключит конфигурационный класс автоматически.
  • Отметим что сам контроллер AppController.java тоже попадет под сканирование компонентов, так как путь к содержащему его пакету указан в @ComponentScan(< "com.elennaro.sshwa.config", "com.elennaro.sshwa.controllers" >) и аннотация @Controller указана для этого класса.
Читайте также:  Как сделать линий в html

Настройки Безопасности (Spring Security — AppSecurityConfig.java, SecurityInit.java)

package com.elennaro.sshwa.config; //Import section ommited. @Configuration @EnableWebSecurity public class AppSecurityConfig extends WebSecurityConfigurerAdapter < @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception < auth.inMemoryAuthentication().withUser("user").password("user").roles("USER"); auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN"); auth.inMemoryAuthentication().withUser("superadmin").password("superadmin").roles("SUPERADMIN"); >@Override protected void configure(HttpSecurity http) throws Exception < http.authorizeRequests() .antMatchers("/protected/**").access("hasRole('ROLE_ADMIN')") .antMatchers("/confidential/**").access("hasRole('ROLE_SUPERADMIN')") .and().formLogin().defaultSuccessUrl("/", false); >> 

Теперь в AppSecurityConfig.java у нас находятся настройки Безопасности а в WebConfig.java настройки MVC. Необходимо удостовериться, что настройки безопасности включены в основной контекст приложения (Иными словами их увидел и втянул в себя Root Application Context). Для этого можно создать класс расширяющий(наследующий) AbstractAnnotationConfigDispatcherServletInitializer. Нам нужно настроить все так чтобы определенный URL паттерн (путь к определенному ресурсу) проходил через уровень безопасности (проходил бы проверку фильтрами Spring Security). Традиционный подход подразумевал настройку сервлет фильтра, в котором мы проверяли бы учетные данные безопасности. С появлением Setvlet 3.x больше нету необходимости объявлять фильтры в web.xml, вся настройка может быть осуществлена с помощью Java классов. Как раз для этого нам нужен AbstractAnnotationConfigDispatcherServletInitializer .

package com.elennaro.sshwa.config; //Import section ommited. public class SecurityInit extends AbstractSecurityWebApplicationInitializer
 springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy  springSecurityFilterChain /* ERROR REQUEST  

Мы закончили настройку MVC и Spring Security. Осталось настроить Диспетчер Сервлета, который отвечает за инициализацию Spring MVC и меппинг URL паттернов. Опять же мы откажемся от традиционной настройки Диспетчера Сервлета через web.xml и будем использовать Java Классы.

Настраиваем Диспетчер Сервлета (WebAppInitializer.java)

WebAppInitializer.java

package com.elennaro.sshwa.config; //Import section ommited. public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer< @Override protected Class[] getRootConfigClasses() < return new Class[] ; // We dont need any special servlet config yet. > @Override protected Class[] getServletConfigClasses() < return null; >@Override protected String[] getServletMappings() < return new String[] ; > > 

Здесь мы настроили мэпинг сервлета на “/” и поэтому все запросы будут перехвачены Диспетчером Сервлета Spring.

Отметим что, наш класс WebAppInitializer.java наследует AbstractAnnotationConfigDispatcherservletinitializergetRootConfigClasses, замещая его метод getRootConfigClasses так чтобы вернуть объявленный нами класс настроек приложения WebConfig.class .
Все… Осталось, прописать вьюшки и попробовать запустить приложение.

Представления (Вьюшки)

   ://$:$$/" />    
Title : $
Message : $
Get protected resource for admin.
Get confidential resource for superadmin.
Updated by Alex Art from in2circle.com
     ://$:$$/" />   Title : $ Message : $  

Welcome : $ " method="post"> " value="$" />

Get protected resource for admin.
Get confidential resource for superadmin.
Updated by Alex Art from in2circle.com

Тут можно толко отметить, что ссылка на logout URL: logout и что по умолчанию тип logout запроса должен быть POST и запрос logout должен содержать csrf token.
Spring Security, сам сгенерирует страницу login.

Финиш.

Как мы и хотели ресурс /helloworld незащищен
Когда же мы поменяем URL на http://localhost:8080/sshwa/protected/ Spring Security перенаправит нас на /login, с формой аутентификации по умолчанию. Если мы введем неверные логин или пароль, будут отображены сообщения об ошибках, и Spring сделает редирект на URL /login?error.
Для неавторизированных пользователей Spring сначала выкинет нас в root («/»), а при следующей попытке зайти на ресурс с неподходящей ролью, отобразит страничку с кодом 403.

Надеюсь в будущем у меня будет время чтобы постепенно развивать этот туториал (в планах перевести все на Spring Boot, а когда выйдет Spring Security 4.0 Release попытаться прикрутить тесты).

На основе материала из источника: javahash.com/spring-security-hello-world-example. Код переработан, текст дополнен кажущимися мне полезными комментариями.

Это мой первый материал, постараюсь учесть все пожелания и замечания.

P.S. Спасибо drno-reg, за то, что нашли ошибку при logout (текст и исходники были обновлены).

Источник

Оцените статью