Spring Security — пример приложения Hello World. Базовые настройки. Spring Security example
Spring Security example — быстрый старт в Spring Security 4. Обзор первоначальных настроек для запуска приложения Hello World с подключенным уровнем безопасности.
Используемые технологии
- Spring 4.2.2.RELEASE
- Spring Security 4.0.2.RELEASE
- JSP 1.2.1
- IntelliJ IDEA 14
- Maven 3.2.5
1. Описание задачи
Необходимо подключить Spring Security 4.0.2 к Spring MVC приложению. Посмотреть как включается аутентификация пользователя, как настроить свою форму для ввода логина и пароля. Настроить форму выхода (logout).
Важно: Перейти на Spring 4 из Spring 3 без дополнительного кода не получится. Т.е. нельзя просто поменять зависимости в pom.xml и расслабиться. В официальной документации есть описание миграции на новую версию. Настройки этой статьи строго для 4+ версии Spring Security.
2 Структура проекта
Создан один MVC @Controller для обработки URL, несколько .jsp представлений с говорящими названиями. Так же в отдельной папке стандартные .xml настройки для Spring. MyBeanPostProcessor используется для отладки и предоставления расширенной информации о работе приложения совместно с log4j.xml.
*В пример намерено не добавляются никакие «красивости» вроде css стилей, bootstrap и т.п.. Так же избегается добавление любой лишней зависимости, чтобы не отвлекать читателя от главной темы статьи.
3. Создание проекта
Создаем пустой проект maven:
файл pom.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ru.javastudy</groupId> <artifactId>springSecurity</artifactId> <version>1.0</version> <properties> <spring-framework-version>4.2.2.RELEASE</spring-framework-version> <spring-security-version>4.0.2.RELEASE</spring-security-version> <slf4j-version>1.7.12</slf4j-version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-framework-bom</artifactId> <version>${spring-framework-version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- Spring security minimal dependency--> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring-security-version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring-security-version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>${spring-security-version}</version> <scope>runtime</scope> </dependency> <!-- Spring MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <!--ExpressionLanguage, Servlet 3.0, JPA 2, EJB, CDI, etc--> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <!--<scope>provided</scope>--> </dependency> <!-- Servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- Logger. Also need to start Tomcat 8+ --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j-version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j-version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j-version}</version> <scope>runtime</scope> </dependency> </dependencies> </project> |
Все зависимости подписаны. Это минимальный набор для запуска Spring MVC + Spring Security + JSP (всё крутится на Tomcat 8).
Добавляем две зависимости для фреймворков (правой кнопкой на название проекта Add frameworks support..)
4. Конфигурация web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!-- - Location of the XML file that defines the root application context - Applied by ContextLoaderListener. --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring/applicationContext.xml /WEB-INF/spring/spring-security-config.xml </param-value> </context-param> <!--Loads the root application context of this web app at startup. The application context is then available via WebApplicationContextUtils.getWebApplicationContext(servletContext). --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Provides core MVC application controller. --> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/spring/dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <!-- Need to enable xml config Spring Security --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- --> <!-- page on load--> <welcome-file-list> <welcome-file>redirectPage.jsp</welcome-file> </welcome-file-list> <!-- error page --> <error-page> <error-code>403</error-code> <location>/accessDenied.jsp</location> </error-page> </web-app> |
Вторая половина конфигурации web.xml требует небольших пояснений. Для xml конфигурации Spring Security необходимо добавить фильтр springSecurityFilterChain (такое название обязательно) и его маппинг. Дальше дописаны страница при старте приложения и страница, которая будет отображаться на 403 коде (доступ запрещен).
5. Конфигурация Spring MVC dispatcher-servlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Dispatcher Servlet - определяет инфраструктуру обработки запросов сервлетом --> <!-- Включает поддержку @Controller и др. в Spring MVC --> <mvc:annotation-driven/> <!-- Обрабатывает HTTP GET запросы для указанного каталога более эффективно для статических ресурсов --> <mvc:resources mapping="/resources/**" location="resources"/> <!-- Определяет какое представление рендерить на основании вычеслений в @Controller (return ModelAndView) --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <!-- Сканирует пакет для поиска бинов --> <context:component-scan base-package="ru.javastudy"/> <!-- Включает Spring аннотации вроде @Autowired --> <context:annotation-config/> </beans> |
Все настройки стандартные и подписаны. Здесь ничего для Spring Security настраивать не нужно.
6. Конфигурация Spring Security spring-security-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<?xml version="1.0" encoding="UTF-8"?> <b:beans xmlns="http://www.springframework.org/schema/security" xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <http realm="JavaStudy example" use-expressions="false"> <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <intercept-url pattern="/admin" access="ROLE_ADMIN"/> <intercept-url pattern="/exitUser*" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <intercept-url pattern="/**" access="ROLE_USER"/> <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1"/> <http-basic/> <logout logout-success-url="/exitUser.jsp"/> <remember-me /> <headers/> <csrf/> </http> <authentication-manager> <authentication-provider> <user-service> <user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" /> <user name="user" password="user" authorities="ROLE_USER" /> <user name="guest" password="guest" authorities="ROLE_GUEST" /> </user-service> </authentication-provider> </authentication-manager> </b:beans> |
- use-expressions — поддержка выражений, при true нужно записывать вот так access = «hasRole(‘ROLE_USER’)»
- intercept-url pattern — шаблон ссылки и у кого есть доступ к ней
- form-login login-page — форма для ввода логина\пароля, которая будет показана для анонимного пользователя куда бы он не пытался войти внутри приложения.
- csrf — Cross Site Request Forgery (описание в отдельном разделе документации). Тут необходимо обратить внимание на дальнейшее использование внутри jsp страницы элемента <c:out value = «${_csrf.token}»/>. Иначе работать приложение не будет.
- remember-me, http-basic, headers — добавлены для примера. Использовать здесь их не обязательно. Подробнее в документации (кратко доступна по ctrl+q в IDEA)
Элемент authentication-manager и дочерние элементы — обязательны. Это всё. Больше для включения базовых настроек Spring Security делать ничего не нужно. Теперь перейдем к представлениям.
7. Описание представлений .jsp
redirectPage.jsp
Страница указана в welcome-file-list, т.е. попадаем в нее на старте приложения. Делает переадресацию по ссылке, которая обрабатывается в контроллере MainController. Это сделано для того, чтобы попасть внутрь приложения в скрытую от внешнего пользователя папку WEB-INF.
1 2 3 4 |
<%@ include file="/WEB-INF/views/include.jsp" %> <%-- Redirected because we can't set the welcome page to a virtual URL. --%> <c:redirect url="/welcome"/> |
login.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page pageEncoding="UTF-8" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Title Login Page</title> </head> <body> <h1>Login page</h1> <p>Valid users: <p>username: <b>user</b>, password: <b>user</b></p> <p>username: <b>admin</b>, password: <b>admin</b></p> <p>username: <b>guest</b>, password: <b>guest</b></p> <c:if test="${not empty param.login_error}"> <span style="color: red; "> Your login attempt was not successful, try again.<br/><br/> Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/> </span> </c:if> <form name="frm" action="<c:url value='login'/>" method="post"> <table> <tr> <td>User:</td> <td><input type="text" name="username"></td></tr> <tr><td>Password:</td> <td><input type="password" name="password"></td></tr> <tr><td colspan="2"><input name="submit" type="submit"></td></tr> <tr><td colspan="2"><input name="reset" type="reset"></td></tr> </table> <input type="hidden" name="<c:out value="${_csrf.parameterName}"/>" value="<c:out value="${_csrf.token}"/>"/> </form> </body> </html> |
Это представление указано как login-page для Spring Security. Сюда будет перенаправлен любой неавторизованный пользователь.
welcomePage.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<%@ include file="/WEB-INF/views/include.jsp" %> <html> <head><title>Welcome page</title></head> <body> <p>This is welcome file page (webapp\WEB-INF\views\welcomePage.jsp). <p>Click button to try security! <p>Click me to go inside app! (link handle by MainController) <a href="<c:url value="/second"/>">Go!</a> <br> <p>Next link for admin only! Try it</p> <a href="<c:url value="/admin"/>">AdminPage</a> </body> </html> |
Это первая страница, куда контроллер перенаправляет после старта приложения. Но т.к. мы еще не авторизованы, то мы попадем на login.jsp.
secondPage.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<%@ include file="/WEB-INF/views/include.jsp" %> <html> <head><title>Index page</title></head> <body> <p>This is secondPage page (webapp\WEB-INF\views\secondPage.jsp). <p>without login you can't see it <form action="<c:url value="/logout"/>" method="post"> <input type="submit" value="Logoff"/> (also clears any remember-me cookie) <security:csrfInput/> </form> </body> </html> |
Вторая страница, куда мы попадем после авторизации. Без прав сюда попасть нельзя.
Остальные страницы accessDenied, exitUser, adminPage представляют собой просто набор текстовой информации для отображения и здесь я их приводить не буду.
8. Контроллер Spring MVC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package ru.javastudy.controllers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import java.security.Principal; @Controller public class MainController { private static final Logger logger = LoggerFactory.getLogger(MainController.class); @RequestMapping(value = "/second") public String indexPage() { return "secondPage"; } @RequestMapping(value = "/admin") public String adminPage() { return "adminPage"; } @RequestMapping(value ="/welcome", method = RequestMethod.GET) public ModelAndView login(@RequestParam(value = "error", required = false) String error) { ModelAndView model = new ModelAndView(); if (error != null) { model.addObject("error", "Invalid username or password!"); } model.setViewName("welcomePage"); return model; } } |
Обычный контроллер с тремя методами. При старте приложения сработает редирект с URL=’/welcome’ и он будет обработан в контроллере. Два других метода срабатывают по указанным ссылкам /second и /admin, висящими на кнопках в представлении seconPage.jsp.
9. Запуск приложения
Рассмотрим последовательность выполнения приложения.
- Срабатывает welcome-file-list из web.xml. Идем в redirectPage.jsp.
- Срабатывает редирект /welcome. Он обрабатывается в контроллере. Идем на страницу welcomePage.jsp, указанной в model контроллера.
- Попадаем на страницу login.jsp! Пользователь не авторизован и согласно настройкам в spring-security-config.xml нас на welcomePage не пускает.
- После успешной авторизации для пользователей с правами user, admin попадаем на welcomePage (или на accsessDenied для guest).
- На второй странице две ссылки. Одна из них сработает только для админа. Go! -> secondPage.jsp; AdminPage -> adminPage.jsp;
- Страница выхода перенаправит после удаления кукисов и т.п. на страницу входа. Ссылка /logout для кнопки разлогина обязательна!
Вот так настраиваются базовые настройки Spring Security 4 для приложения Hello World;
P.S. папка web после добавления фреймворков переименована в webapp. Не забудьте исправить, если будете копировать код.
Исходный код
212 thoughts on “Spring Security — пример приложения Hello World. Базовые настройки. Spring Security example”
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.
<!— page on load—>
<welcome—file—list>
<welcome—file>redirectPage.jsp</welcome—file>
</welcome—file—list>
это не срабатывает даже в с твоими исходниками,многие важные моменты упущены, причем во всех статьях, представленные примеры не являются авторскими, прояви немного уважения к читателям и приведи материал в нормальное состояние.
Добавьте «многие важные моменты во всех статьях» для других читателей в комментариях. Они будут вам благодарны.
*P.S. код из исходников в конце статьи работает как задумано и redirect тоже:) Заметил только косяк в adminp (p тег не обернут правильно. Должно быть admin admin)