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 г. 5:30
Продолжение будет цикла? Очень класно написано. В частносте хотелось бы увидеть как выглядит вся эта конфигурация spring security без spring-security-config, т.е. на чистых бинах. Это нужно для того, чтоб понимать, что там происходит внутри. Я лично уже начал с этим разбираться, но пока не нашел лучшей доки чем исходники самого спринга...
Вы должны войти под своим аккаунтом чтобы оставлять комментарии