Spring EL expressions в Spring Security

липня
05
2012

Зміст

Як уже згадувалося в попередній, ця стаття буде присвячена використанню виразів Spring EL expressions в Spring Security. Будуть розглянуті всі можливі стандартні вирази.

Отже, приступимо... З попередньої статті стало зрозуміло, що для використання виразів в тезі http налаштувань безпеки необхідно додати атрибут use-expressions зі значенням true:


<http auto-config="true" use-expressions="true">
	...
</http>

Кожний розглянутий вираз буде супроводжуватися прикладом для полегшення розуміння.

hasRole([role]) - повертає true якщо поточний користувач має зазначену роль:


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/secure/**" access="hasRole('ROLE_USER')" />
</http>

hasAnyRole([role1,role2]) - повертає true якщо поточний користувач має будь-яку із зазначених ролей:


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/hasanyrole/**" access="hasAnyRole('ROLE_ADMIN,ROLE_USER')" />
</http>

principal - дає прямий доступ до об'єкта користувача:


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/principal/**" access="isAuthenticated() and principal.username == 'admin'" />
</http>	

authentication - дає прямий доступ до об'єкта Authentication:


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/authentication/**" access="authentication.name == 'admin'" />
</http>

permitAll - завжди повертає true (застосовується для публічного і статичного контенту):


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/public/**" access="permitAll" />
</http>

denyAll - завжди повертає false. Найбільш часто застосовується як завершальне правило, яке забороняє всі адреси, які не були описані правилами (вибір правила в Spring Security відбувається зверху вниз):


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/public/**" access="permitAll" />
	<intercept-url pattern="/**" access="denyAll" />
</http>

isAnonymous() - повертає true якщо поточний користувач не авторизований:


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/anonymousonly/**" access="isAnonymous()" />
</http>	

У наведеному вище прикладі авторизований користувач не матиме доступу до вказаних адрес.

isRememberMe() - повертає true якщо користувач авторизований за допомогою можливості "Запам'ятати мене":


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/remembermeonly/**" access="isRememberMe()" />
</http>	

isAuthenticated() - повертає true якщо користувач авторизований:


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/authenticatedonly/**" access="isAuthenticated()" />
</http>	

isFullyAuthenticated() - повертає true якщо користувач авторизований без допомоги можливості "Запам'ятати мене":


<http auto-config="true" use-expressions="true">
	<intercept-url pattern="/fullyauthenticatedonly/**" access="isFullyAuthenticated()" />
</http>	

Є ще один додатковий вираз hasIpAddress з класу WebSecurityExpressionRoot:


<http use-expressions="true">
    <intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN') and hasIpAddress('192.168.1.0/24')"/>
</http>

Також в Spring Security є можливість створювати свої власні вирази.

Ви можете використовувати вирази не тільки в тезі http, а й у своїх методах. Для цього необхідно трохи відкоригувати конфігурацію веб-програми. Додайте в контексті сервлета (не в конфігурації безпеки!) наступний код:


<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	...
	xmlns:sec="http://www.springframework.org/schema/security"
	xsi:schemaLocation="
                ...
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

	<sec:global-method-security pre-post-annotations="enabled" />
	
</beans:beans>

Повний servlet-context.xml виглядає наступним чином:

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:sec="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

	<annotation-driven />

	<resources mapping="/resources/**" location="/resources/" />

	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<context:component-scan base-package="com.seostella.springsecurityel" />
	
	<sec:global-method-security pre-post-annotations="enabled" />
	
</beans:beans>

А в pom.xml ще одну залежність:


<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>2.2.2</version>
</dependency>

Тепер Ви можете використовувати чотири анотації в методах своїх класів: @PreAuthorize, @PreFilter, @PostAuthorize і @PostFilter. Наприклад, так:


@PreAuthorize("hasRole('ROLE_GREETING')")
@ModelAttribute("greeting")
public String populateGreeting() {
	return "Hi User!";
}

У разі якщо користувач не має ролі ROLE_GREETING, він побачить сторінку з помилкою 403.

Також є можливість додавання зрізів за допомогою protect-pointcut. Вам доведеться змінити тег global-method-security наприклад так:


<sec:global-method-security
	pre-post-annotations="enabled">
	<sec:protect-pointcut
		expression="execution(* com.seostella.springsecurityel.controller.SecureController.*(..))"
		access="ROLE_GREETING" />
</sec:global-method-security>

У файл pom.xml також потрібно додати залежність:


<dependency>
	<groupId>aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.5.3</version>
</dependency>

Тепер всі методи класу SecureController будуть виконувати тільки якщо в користувача є роль ROLE_GREETING.

< Logout в Spring Security

Коментарі (4)

SpokeU
25 жовтня 2012 р. 15:22
Класний сайт) чого ніде нема коментарів?)
lehvolk
27 травня 2013 р. 16:08
Отличный обзор. Спасибо.
andydoroga1989
3 вересня 2013 р. 23:40
Спасибо. Очень просто и доступно описано. Никаких лишних рассуждений.
msangel
20 жовтня 2013 р. 05:30
Продолжение будет цикла? Очень класно написано. В частносте хотелось бы увидеть как выглядит вся эта конфигурация spring security без spring-security-config, т.е. на чистых бинах. Это нужно для того, чтоб понимать, что там происходит внутри. Я лично уже начал с этим разбираться, но пока не нашел лучшей доки чем исходники самого спринга...
Ви повинні увійти під своїм аккаунтом щоб залишати коментарі