1. Обзор
В этом кратком руководстве мы рассмотрим, как защитить веб-приложение Jakarta EE с помощью Spring Security .
2. Зависимости Maven
Давайте начнем с необходимых зависимостей Spring Security для этого руководства :
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
Последняя версия Spring Security (на момент написания этого руководства) — 4.2.3.RELEASE; как всегда, мы можем проверить Maven Central на наличие новейших версий.
3. Конфигурация безопасности
Далее нам нужно настроить конфигурацию безопасности для существующего приложения Jakarta EE:
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig
extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password("user1Pass").roles("USER")
.and()
.withUser("admin").password("adminPass").roles("ADMIN");
}
}
В методе configure()
мы настраиваем AuthenticationManager
. Для простоты мы реализуем простую аутентификацию в памяти. Данные пользователя жестко закодированы.
Это предназначено для быстрого прототипирования, когда нет необходимости в полном механизме персистентности.
Далее интегрируем безопасность в существующую систему, добавив класс SecurityWebApplicationInitializer :
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(SpringSecurityConfig.class);
}
}
Этот класс обеспечит загрузку SpringSecurityConfig
во время запуска приложения. На этом этапе мы достигли базовой реализации Spring Security . В этой реализации Spring Security будет требовать аутентификацию для всех запросов и маршрутов по умолчанию.
4. Настройка правил безопасности
Мы можем дополнительно настроить Spring Security, переопределив метод
configure( HttpSecurity http) WebSecurityConfigurerAdapter
:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/auth/login*").anonymous()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/auth/login")
.defaultSuccessUrl("/home", true)
.failureUrl("/auth/login?error=true")
.and()
.logout().logoutSuccessUrl("/auth/login");
}
Используя метод antMatchers()
, мы настраиваем Spring Security, чтобы разрешить анонимный доступ к /auth/login
и `` аутентифицировать любой другой запрос.
4.1. Пользовательская страница входа
Пользовательская страница входа настраивается с помощью метода formLogin()
:
http.formLogin()
.loginPage("/auth/login")
Если это не указано, Spring Security создает страницу входа по умолчанию в /login
:
<html>
<head></head>
<body>
<h1>Login</h1>
<form name='f' action="/auth/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>
4.2. Пользовательская целевая страница
После успешного входа Spring Security перенаправляет пользователя в корень приложения. Мы можем переопределить это, указав URL-адрес успеха по умолчанию:
http.formLogin()
.defaultSuccessUrl("/home", true)
Установив для параметра alwaysUse метода defaultSuccessUrl
()
значение true, пользователь всегда будет перенаправляться на указанную страницу. ``
Если параметр alwaysUse
не установлен или имеет значение false, пользователь будет перенаправлен на предыдущую страницу, к которой он пытался получить доступ, прежде чем ему будет предложено пройти аутентификацию.
Точно так же мы также можем указать пользовательскую целевую страницу отказа:
http.formLogin()
.failureUrl("/auth/login?error=true")
4.3. Авторизация
Мы можем ограничить доступ к ресурсу по роли:
http.formLogin()
.antMatchers("/home/admin*").hasRole("ADMIN")
Пользователь без прав администратора получит сообщение об ошибке «Отказано в доступе», если попытается получить доступ к конечной точке /home/admin
.
Мы также можем ограничить данные на странице JSP в зависимости от роли пользователя. Это делается с помощью тега <security:authorize>
:
<security:authorize access="hasRole('ADMIN')">
This text is only visible to an admin
<br/>
<a href="<c:url value="/home/admin" />">Admin Page</a>
<br/>
</security:authorize>
Чтобы использовать этот тег, мы должны включить теги Spring Security taglib вверху страницы:
<%@ taglib prefix="security"
uri="http://www.springframework.org/security/tags" %>
5. XML-конфигурация безопасности Spring
До сих пор мы рассматривали настройку Spring Security в Java. Давайте взглянем на эквивалентную конфигурацию XML.
Во- первых, нам нужно создать файл security.xml в папке
web/WEB-INF/spring
, который содержит наши XML-конфигурации. Пример такого конфигурационного файла security.xml
доступен в конце статьи.
Начнем с настройки диспетчера аутентификации и поставщика аутентификации. Для простоты мы используем простые жестко заданные учетные данные пользователя:
<authentication-manager>
<authentication-provider>
<user-service>
<user name="user"
password="user123"
authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
Мы только что создали пользователя с именем пользователя, паролем и ролью.
В качестве альтернативы мы можем настроить нашего поставщика аутентификации с кодировщиком паролей:
<authentication-manager>
<authentication-provider>
<password-encoder hash="sha"/>
<user-service>
<user name="user"
password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f"
authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
Мы также можем указать пользовательскую реализацию Spring UserDetailsService
или Datasource
в качестве нашего поставщика аутентификации. Более подробную информацию можно найти здесь.
Теперь, когда мы настроили менеджер аутентификации, давайте настроим правила безопасности и применим контроль доступа:
<http auto-config='true' use-expressions="true">
<form-login default-target-url="/secure.jsp" />
<intercept-url pattern="/" access="isAnonymous()" />
<intercept-url pattern="/index.jsp" access="isAnonymous()" />
<intercept-url pattern="/secure.jsp" access="hasRole('ROLE_USER')" />
</http>
В приведенном выше фрагменте мы настроили HttpSecurity
для использования формы входа и установили /secure.jsp
в качестве URL-адреса успешного входа. Мы предоставили анонимный доступ к /index.jsp
и пути «/»
. Кроме того, мы указали, что доступ к /secure.jsp
должен требовать аутентификации, а аутентифицированный пользователь должен иметь как минимум уровень полномочий ROLE_USER
.
Установка для атрибута auto-config
тега http значения
true
указывает Spring Security реализовать поведение по умолчанию, которое нам не нужно переопределять в конфигурации. Поэтому /login
и /logout
будут использоваться для входа и выхода пользователя соответственно. Также предоставляется страница входа по умолчанию.
Мы можем дополнительно настроить тег form-login
с пользовательскими страницами входа и выхода, URL-адресами для обработки как неудачной, так и успешной аутентификации. В приложении Security Namespace перечислены все возможные атрибуты для тегов form-login (и других).
Некоторые IDE также позволяют проводить проверку, щелкая тег при нажатой клавише ctrl .
Наконец, чтобы конфигурация security.xml
загружалась во время запуска приложения, нам нужно добавить следующие определения в наш web.xml
:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/*.xml
</param-value>
</context-param>
<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>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Обратите внимание, что попытка использовать конфигурации на основе XML и Java в одном и том же приложении JEE может привести к ошибкам.
6. Заключение
В этой статье мы увидели, как защитить приложение Jakarta EE с помощью Spring Security, и продемонстрировали конфигурации как на основе Java, так и на основе XML.
Мы также обсудили способы предоставления или отзыва доступа к определенным ресурсам в зависимости от роли пользователя.
Полный исходный код и определения XML доступны на GitHub .