barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

вторник, 10 января 2012 г.

Небольшое HOWTO по прикручиванию авторизации и аутентификации с помощью Spring Security к уже существующему веб-приложению

Итак, изначально ситуация была следующая: есть небольшое веб-приложение на JSP, не использующее никаких фреймворков. Задача - добавить в него авторизацию и аутентификацию с помощью фреймворка Spring Security.
Поискав в инете я так и не нашел какого-нибудь работающего примера как сделать так, чтобы "оно заработало", а потом уже разбираться в тонкостях и возможностях Spring Security. Примеры были либо непонятные, либо по Spring Security 2.х, тогда как мне хотелось работать сразу с 3.х (точнее, 3.1).
После некоторых проб и ошибок получилось найти следующий алгоритм:
1) Подключаем к проекту библиотеки спринга:
  • org.springframework.core-3.1.0.RELEASE.jar
  • org.springframework.beans-3.1.0.RELEASE.jar
  • org.springframework.context-3.1.0.RELEASE.jar
  • org.springframework.expression-3.1.0.RELEASE.jar
  • org.springframework.web-3.1.0.RELEASE.jar
2) Подключаем библиотеки Spring Security:
  • spring-security-core-3.1.0.RELEASE.jar
  • spring-security-config-3.1.0.RELEASE.jar
  • spring-security-web-3.1.0.RELEASE.jar
3) Добавляем в web.xml следующие строки:
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
- для инициализации контекста спринга в целом
    <context-param>
        <param-name>
            contextConfigLocation
            </param-name>
        <param-value>
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param> 
- для установки пути к файлу конфигурации Spring
    <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> 
- для добавления фильтра Spring Security на все страницы

4) Создаем в WEB-INF/ файл конфигурации спринга spring-security.xml и добавляем в него:

<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">


    <!--Public resources -->
    <http pattern="/js/**" security="none"/>
    <http pattern="/style/**" security="none"/>
    <http pattern="/img/**" security="none"/>

    <http pattern="/login.jsp" security="none"/> 
    <http auto-config="true" access-denied-page="/login.jsp?accessDeniedError=1">
        <intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN
" />
        <form-login authentication-failure-url="/login.jsp?loginError=1"
                    login-page="/login.jsp"
                    login-processing-url="/j_spring_security_check"/>
    </http>

    <authentication-manager>
        <authentication-provider >
            <password-encoder hash="md5" />
            <user-service>
                <user name="test" password="098f6bcd4621d373cade4e832627b4f6" authorities="ROLE_USER,ROLE_ADMIN" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
    <beans:bean id="loginSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler" >
        <beans:property name="defaultTargetUrl" value="/index.jsp"/>
        <!--beans:property name="redirectStrategy" ref="defaultRedirectStrategy"/-->
    </beans:bean>
    <beans:bean id="loginFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler" >
        <beans:property name="defaultFailureUrl" value="/login.jsp?loginError=1" />
    </beans:bean>
</beans:beans>
Что в приведенном выше конфиге делается:
  • Устанавливается страница, отображаемая если на запрошенный ресурс не хватает прав у пользователя: login.jsp?accessDeniedError=1
  • Устанавливается страница, на которой будет размещена форма для ввода логина / пароля: login.jsp (на неё идет редирект если пользователь ещё не авторизован). Эта страница будет, естественно, доступна не авторизованным пользователям.
  • Устанавливается страница, куда идет редирект при неуспешной авторизации: login.jsp?loginError=1
  • Устанавливается страница, на котороую идет редирект после успешной авторизации: index.jsp
  • Пользователи задаются прямо в конфигурации, создается один пользователь с логином / паролем test/test (пароль захэширован по алгоритму md5) и ролями USER и ADMIN
  • Устанавливается путь, по которому размещается обработчик авторизации: j_spring_security_check (обработчик будет размещен спрингом автоматически, поэтому без разницы, какой урл указывать, главное чтобы он не конфликтовал с уже существующими)
  • Устанавливается ограничение на доступ ко всем страницам, кроме login.jsp, позволяющее иметь к этой странице доступ только пользователям с ролью USER или ADMIN
  • Доступ к всем элементам директорий js, style и img делается открытым (не требующим аутентификации)
5) Создаем форму авторизации. В ней указываем в качестве action="j_spring_security_check", а поля имени пользователя и пароля называем, соответственно, "j_username" и "j_password".
6) Разавторизация может осуществляется кодом:
SecurityContextHolder.getContext().setAuthentication(null);
Правда, этот код нельзя вызывать на login.jsp, т.к. она помечена как незащищенная, и, следовательно, на ней контекст безопасности недоступен (такой вызов попросту ни к чему не приведет). Чтобы решить эту проблему, понадобится следующая конфигурация:
     <!--Public resources -->
    <http pattern="/js/**" security="none"/>
    <http pattern="/style/**" security="none"/>
    <http pattern="/img/**" security="none"/>
    <!-- login.jsp is under spring security control, but is accessible anonimously -->
    <http pattern="/login.jsp">
        <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        <form-login authentication-failure-url="/login.jsp?loginError=1"
                    login-page="/login.jsp"
                    login-processing-url="/j_spring_security_check"/>
    </http>
    <http auto-config="true" access-denied-page="/login.jsp?accessDeniedError=1">
        <intercept-url pattern="/**" access="ROLE_USER" />
        <form-login authentication-failure-url="/login.jsp?loginError=1"
                    login-page="/login.jsp"
                    login-processing-url="/j_spring_security_check"/>
    </http>
В прочем, разавторизацию можно сделать и проще, перейдя на URL "/j_spring_security_logout" (этот URL можно при желании переопределить в конфиге). После перехода на него произойдет разавторизация и редирект на страницу логина. 

1 комментарий:

  1. Хм... а можно ссылку на то, где взять библиотеки?

    ОтветитьУдалить