четверг, 14 февраля 2013 г.

Создание приложения Spring Security с нуля

Имеем 
  • Eclipse IDE for java EE developers 4.2.1
  • apache tomcat 7.0.35
Создаём в eclipse новый проект File > New > Project > Web > Dynamic Web Project.
Project name = springsecurity


Чего хотим в конце? -
  • страничку авторизации на основе jsp, чтобы в наше приложение могли зайти только правильные пользователи, и чтобы каждому зашедшему мы могли выдать его информацию и ничью больше.
  • на всех защищённых страницах должна быть ссылка логаута, после клика по которой клиентский компьютер и сервер должны забыть, кто только что был авторизован.
В этом примере не будет ни одного java-класса, здесь рассматриваются только вопросы конфигурирования приложения с помощью xml-файлов и некоторые 
 
Эта статья является упрощением англоязычной статьи, находящейся здесь.

По этой ссылке скачиваем Spring security, распаковываем архив и в папке dist видим там около 11 jar-файлов библиотек и такое же количество соответствующих им source.jar и javadoc.jar. Кроме того в этой папке должна быть пара war-архивов. Мы будем пользоваться архивом spring-security-samples-tutorial-3.1.2.RELEASE.war (ваша версия может быть другой).

Вообще-то это вполне законченное web-приложение. Этот архив можно положить в папку webapps своего томката, запустить его и посмотреть на результат в браузере по адресу:
http://localhost:8080/spring-security-samples-tutorial-3.1.2.RELEASE

Но поскольку мы хотим всё сделать сами, мы воспользуемся этим архивом, чтобы вытащить из него всё самое ценное, а потом сверху поместить свой логотип.

Поэтому разархивируем вышеуказанный war-архив и из папки WEB-INF/lib забираем все jar-ы в аналогичную папку своего проекта:
  • aopalliance-1.0.jar
  • jcl-over-slf4j-1.6.1.jar
  • jstl-1.2.jar
  • logback-classic-0.9.29.jar
  • logback-core-0.9.29.jar
  • slf4j-api-1.6.1.jar
  • spring-aop-3.0.7.RELEASE.jar
  • spring-asm-3.0.7.RELEASE.jar
  • spring-beans-3.0.7.RELEASE.jar
  • spring-context-3.0.7.RELEASE.jar
  • spring-context-support-3.0.7.RELEASE.jar
  • spring-core-3.0.7.RELEASE.jar
  • spring-expression-3.0.7.RELEASE.jar
  • spring-security-config-3.1.2.RELEASE.jar
  • spring-security-core-3.1.2.RELEASE.jar
  • spring-security-crypto-3.1.2.RELEASE.jar
  • spring-security-taglibs-3.1.2.RELEASE.jar
  • spring-security-web-3.1.2.RELEASE.jar
  • spring-web-3.0.7.RELEASE.jar
  • spring-webmvc-3.0.7.RELEASE.jar

В папке WEB-INF создаём файл web.xml:

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <display-name>Spring Security Tutorial Application</display-name>

    <!--
      - Location of the XML file that defines the root application context
      - Applied by ContextLoaderListener.
      -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:applicationContext-security.xml
        </param-value>
    </context-param>

    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>tutorial.root</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>

    <!--
      - Loads the root application context of this web app at startup.
    -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--
      - Publishes events for session creation and destruction through the application
      - context. Optional unless concurrent session control is being used.
      -->
    <listener>
      <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>

  <!--
    - Provides core MVC application controller. Требует наличия файла bank-servlet.xml.
    -->
    <servlet>
        <servlet-name>bank</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>bank</servlet-name>
        <url-pattern>*.html</url-pattern>
     </servlet-mapping>

     <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

</web-app>

Поскольку мы в web.xml объявили сервлет bank, мы обязаны создать в той же папке /war/WEB-INF конфигурационный файл для него bank-servlet.xml (имя этого конфигурационного файла формируется путём дописывания к имени сервлета строки "-servlet.xml"):

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="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-3.0.xsd">
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>


В папку src кладём xml-файл:
  • applicationContext-security.xml

<?xml version="1.0" encoding="UTF-8"?>

<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-3.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

<!-- тег, ответственный за очень подробное логирование при использовании spring security -->
    <debug />

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

    <http pattern="/static/**" security="none"/>
    <http pattern="/loggedout.jsp" security="none"/>

    <http use-expressions="true">
        <intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')"/>
        <intercept-url pattern="/secure/**" access="isAuthenticated()" />
        <!--
             Allow all other requests. In a real application you should
             adopt a whitelisting approach where access is not allowed by default
          -->
        <intercept-url pattern="/**" access="permitAll" />
        <form-login />
        <logout logout-success-url="/loggedout.jsp" delete-cookies="JSESSIONID"/>
        <remember-me />
<!--
    Uncomment to enable X509 client authentication support
        <x509 />
-->
        <!-- Uncomment to limit the number of sessions a user can have -->
        <!-- 
        <session-management invalid-session-url="/timeout.jsp">
            <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
        </session-management>
 -->
    </http>

    <!--
    Usernames/Passwords are
        rod/koala
        dianne/emu
        scott/wombat
        peter/opal
    -->
    <beans:bean id="encoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"/>

    <authentication-manager>
        <authentication-provider>
            <password-encoder ref="encoder"/>
            <user-service>
                <user name="rod" password="4efe081594ce25ee4efd9f7067f7f678a347bccf2de201f3adf2a3eb544850b465b4e51cdc3fcdde" authorities="supervisor, user, teller" />
                <user name="dianne" password="957ea522524a41cbfb649a3e293d56268f840fd5b661b499b07858bc020d6d223f912e3ab303b00f" authorities="user,teller" />
                <user name="scott" password="fb1f9e48058d30dc21c35ab4cf895e2a80f2f03fac549b51be637196dfb6b2b7276a89c65e38b7a1" authorities="user" />
                <user name="peter" password="e175750688deee19d7179d444bfaf92129f4eea8b4503d83eb8f92a7dd9cda5fbae73638c913e420" authorities="user" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

</beans:beans>



Так же из этого проекта из папки \war возьмём  jsp-файлы и css, считая, что их кастомизация - это отдельная деятельность, которая мало связана с настройкой безопасности. Копируем файлы:
  • index.jsp - стартовая страница приложения
  • loggedout.jsp - страница, куда будет перенаправлен пользователь после логаута
  • timeout.jsp - страница, куда будет перенаправлен пользователь после истечения времени жизни сессии (и какой-то другой недействительности сессии)
  • secure/index.jsp - безопасная страница, доступ к ней предоставляется только когда метод isAuthenticated() возвращает true
  • secure/extreme/index.jsp - особо безопасная страница для пользователей с заданной ролью supervisor
  • static/css/tutorial.css - файл стилей приложения

index.jsp

<%@ page session="false" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
  <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <link rel="stylesheet" href="<c:url value='/static/css/tutorial.css'/>" type="text/css" />
      <title>Home Page</title>
  </head>
<body>
<div id="content">
<h1>Home Page</h1>
<p>
Anyone can view this page.
</p>
<p>
While anyone can also view the <a href="listAccounts.html">list accounts</a> page, you must be authorized to post to an Account from the list accounts page.
</p>
<p>
Your principal object is....: <%= request.getUserPrincipal() %>
</p>
<sec:authorize url='/secure/index.jsp'>
<p>
You can currently access "/secure" URLs.
</p>
</sec:authorize>
<sec:authorize url='/secure/extreme/index.jsp'>
<p>
You can currently access "/secure/extreme" URLs.
</p>
</sec:authorize>

<p>
<a href="secure/index.jsp">Secure page</a></p>
<p><a href="secure/extreme/index.jsp">Extremely secure page</a></p>
</div>
</body>
</html>

loggedout.jsp
<%@page session="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
  <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <link rel="stylesheet" href="<c:url value='/static/css/tutorial.css'/>" type="text/css" />
      <title>Logged Out</title>
  </head>
<body>
<div id="content">
<h2>Logged Out</h2>
<p>
You have been logged out. <a href="<c:url value='/'/>">Start again</a>.
</p>
</div>
</body>
</html>

timeout.jsp
<%@page session="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
  <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <link rel="stylesheet" href="<c:url value='/static/css/tutorial.css'/>" type="text/css" />
      <title>Session Timeout</title>
  </head>
<body>
<div id="content">
<h2>Invalid Session</h2>

<p>
Your session appears to have timed out. Please <a href="<c:url value='/'/>">start again</a>.
</p>
</div>
</body>
</html>

secure/index.jsp
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
  <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <link rel="stylesheet" href="<c:url value='/static/css/tutorial.css'/>" type="text/css" />
      <title>Secure Page</title>
  </head>
<body>
<div id="content">

<h1>Secure Page</h1>
<p>
This is a protected page. You can get to me if you've been remembered,
or if you've authenticated this session.
</p>
<p>
<sec:authorize access="hasRole('supervisor')">
    You are a supervisor! You can therefore see the <a href="extreme/index.jsp">extremely secure page</a>.<br/><br/>
</sec:authorize>
</p>
<h3>Properties obtained using &lt;sec:authentication /&gt; tag</h3>
<table border="1">
<tr><th>Tag</th><th>Value</th></tr>
<tr>
<td>&lt;sec:authentication property='name' /&gt;</td><td><sec:authentication property="name"/></td>
</tr>
<sec:authorize access="isAuthenticated()">
<tr>
<td>&lt;sec:authentication property='principal.username' /&gt;</td><td><sec:authentication property="principal.username"/></td>
</tr>
<tr>
<td>&lt;sec:authentication property='principal.enabled' /&gt;</td><td><sec:authentication property="principal.enabled"/></td>
</tr>
<tr>
<td>&lt;sec:authentication property='principal.accountNonLocked' /&gt;</td><td><sec:authentication property="principal.accountNonLocked"/></td>
</tr>
</sec:authorize>
</table>

<p><a href="../">Home</a></p>
<p><a href="../j_spring_security_logout">Logout</a></p>
</div>
</body>
</html>

secure/extreme/index.jsp
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
  <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <link rel="stylesheet" href="<c:url value='/static/css/tutorial.css'/>" type="text/css" />
      <title>Secure Page</title>
  </head>
<body>
<div id="content">
<h1>VERY Secure Page</h1>
This is a protected page. You can only see me if you are a supervisor.

<authz:authorize access="hasRole('supervisor')">
   You have authority "supervisor" (this text is surrounded by &lt;authz:authorize&gt; tags).
</authz:authorize>

<p><a href="../../">Home</a></p>
<p><a href="../../j_spring_security_logout">Logout</a></p>
</div>
</body>
</html>

static/css/tutorial.css

body {
    font-family:"Palatino Linotype","Book Antiqua",Palatino,serif;
}

#content {
    margin: 5em auto;
    width: 40em;
}

.securityHiddenUI, .securityHiddenUI * {
    background-color: #ff4500;
}


Итоговая структура файлов и папок должна выглядеть так:

Комментариев нет:

Отправить комментарий