Перейти к основному содержимому

Защита Jakarta EE с помощью Spring Security

· 5 мин. чтения

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 .