Внедрение Spring Security в связку ZK+Spring Framework+Hibernate: часть первая

    Всем доброго времени суток. Как и обещал, попытаюсь осветить тему секьюрности в веб-приложении, написанном на ZK Framework. Почему часть первая? Потому что в данной статье я покажу вам наиболее быстрый и простой метод внедрения Spring Security с использованием в качестве страницы авторизации- jsp страницу; в последующей(их) статье(ях) будут описаны более сложные и интересные методы с использованием zul в качестве построения страницы авторизации.
    Веб-приложение писать с нуля не будем, а за основу возьмем мое прошлое приложение, которое я описывал в этом топике.
    Что нам понадобится:
    Данный метод можно реализовывать тоже по-разному, либо хранить юзеров, их пароли и права в xml конфигурации Spring Security, либо хранить в базе данных. Так как наше приложение и так работает с базой Oracle, так чего бы и юзеров не хранить в базе. Как говорит нам документация спринга, при дефолтном развертывании Spring Security смотрит в базу на 2 таблицы (users и authorities). При групповой политики, требуется наличие еще и таких таблиц, как :groups, group_authorities, group_members (скрипты таблиц можно взять отсюда).

    Значит создаем в базе 2 таблицы вида:

    CREATE TABLE users
    (
        username   varchar2 (50) NOT NULL PRIMARY KEY,
        password   varchar2 (50) NOT NULL,
        enabled    number NOT NULL
    );
    



    CREATE TABLE authorities
    (
        username    varchar2 (50) NOT NULL,
        authority   varchar2 (50) NOT NULL,
        CONSTRAINT fk_authorities_users FOREIGN KEY
            (username)
             REFERENCES users (username)
    );
    
    CREATE UNIQUE INDEX ix_auth_username
        ON authorities (username, authority);
    

    Следующим шагом сконфигурируем наш Spring Security. В файл spring-config.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" xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:security="http://www.springframework.org/schema/security"
    	xmlns:tx="http://www.springframework.org/schema/tx"
    	xsi:schemaLocation="
    		http://www.springframework.org/schema/beans
    		http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    		http://www.springframework.org/schema/context
    		http://www.springframework.org/schema/context/spring-context-3.1.xsd
    		http://www.springframework.org/schema/tx
    		http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
    		http://www.springframework.org/schema/security
            http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    	<context:annotation-config />
    	<context:component-scan base-package="com.sample" />
    	<tx:annotation-driven transaction-manager="txManager" />
    	
    	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    		<property name="jndiName">
    			<value>java:comp/env/jdbc/taskdb</value>
    		</property>
    	</bean>
    	
    	<bean id="txManager"
    		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="dataSource" ref="dataSource" />
    		<property name="sessionFactory" ref="sessionFactory" />
    	</bean>
    	<bean id="sessionFactory"
    		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    		<property name="dataSource">
    			<ref bean="dataSource" />
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
    				<prop key="hibernate.show_sql">false</prop>
    				<!--<prop key="hibernate.hbm2ddl.auto">update</prop> -->
    			</props>
    		</property>
    		<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    		<property name="configLocation" value="/WEB-INF/hibernate.cfg.xml" />
    	</bean>
    	<!-- Configure the Spring Security -->
    	<security:global-method-security
    		secured-annotations="enabled" jsr250-annotations="enabled" />
    


    	<security:http auto-config="true">
    		<!-- Don't set any role restrictions on login.jsp -->
    		<security:intercept-url pattern="/login.jsp"
    			access="IS_AUTHENTICATED_ANONYMOUSLY" />
    		<!-- Restrict access to ALL other pages -->
    		<security:intercept-url pattern="/**"
    			access="ROLE_ADMIN,ROLE_USER" />
    		<security:form-login login-page="/login.jsp"
    			default-target-url="/index.zul" always-use-default-target="true"
    			authentication-failure-url="/login.jsp?login_error=1" />
    		<security:logout logout-url="/j_spring_security_logout"
    			invalidate-session="true" logout-success-url="/logoutSuccess.jsp" />
    	</security:http>
    	<!-- Configure the authentication provider -->
    	<security:authentication-manager>
    		<security:authentication-provider>
    			<security:jdbc-user-service
    				data-source-ref="dataSource" />
    		</security:authentication-provider>
    	</security:authentication-manager>
    </beans>
    

    Остановлюсь на некоторых моментах:
    • <security:global-method-security
      secured-annotations="enabled" jsr250-annotations="enabled" />
      — дает нам возможность использовать аннотации вида @RolesAllowed(«ROLE_ADMIN»), для группы прав данная строка будет иметь вид @RolesAllowed({«ROLE_ADMIN»,«ROLE_USER»});
    • <security:intercept-url pattern="/login.jsp"
      access="IS_AUTHENTICATED_ANONYMOUSLY" />
      — говорим, что все могут заходить на страницу login.jsp;
    • <security:intercept-url pattern="/**"
      access="ROLE_ADMIN,ROLE_USER" />
      — только пользователи, которые имеют права ROLE_ADMIN и/или ROLE_USER могут заходить на все страницы
    • <security:form-login login-page="/login.jsp"
      default-target-url="/index.zul" always-use-default-target="true"
      authentication-failure-url="/login.jsp?login_error=1" />
      — при правильном логине/пароле переходим на страницу index.zul (конечно если права у данного пользователя позволяют это сделать), в противном случае выводим код ошибки.

    Также не забудем добавить в web.xml:
             <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>
    

    Все, с конфигурацией покончено. Теперь напишем страничку авторизации login.jsp.
    <%@ page language="java" contentType="text/html; charset=utf-8"
    	pageEncoding="utf-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt'%>
    <html>
    <head>
    <title>Форма Авторизации</title>
    <style type="text/css">
    body {
    	background: #63bad8 50% 0px repeat-x;
    	text-align: center;
    }
    
    div.main {
    	margin: 50px auto;
    	padding: 0 0 0 0;
    	width: 340px;
    	border-color: black;
    }
    </style>
    </head>
    <body>
    	<div class="main">
    		<h1
    			style="background-color: #3F3F3F; color: white; padding: 0px; margin: 0px;">Авторизация</h1>
    		<div
    			style="background: white; border: black; padding: 0px; margin: 0px;"
    			align="center" dir="ltr">
    			<c:if test="${not empty param.login_error}">
    				<font color="red"> Не правильный логин или пароль. Попробуйте
    					заново.</font>
    			</c:if>
    			<form name="f" action="<c:url value='j_spring_security_check'/>"
    				method="POST" style="background: white;">
    				<table>
    					<tr>
    						<td style="font-style: oblique">Пользователь:</td>
    						<td><input type='text' name='j_username'
    							value='<c:if test="${not empty param.login_error}"><c:out value="${SPRING_SECURITY_LAST_USERNAME}"/></c:if>' />
    						</td>
    					</tr>
    					<tr>
    						<td style="font-style: oblique">Пароль:</td>
    						<td><input type='password' name='j_password'>
    						</td>
    					</tr>
    					<tr align="center">
    						<td colspan='2' align="center"><input name="submit"
    							value="Войти" type="submit"> <input name="reset"
    							value="Очистить" type="reset">
    						</td>
    					</tr>
    				</table>
    			</form>
    		</div>
    	</div>
    </body>
    </html>
    

    Можно запускать и смотреть на наши плоды.
    Давайте теперь поиграемся с разграничением прав. К примеру, разрешим только пользователю с правами ROLE_ADMIN, удалять пользователей из системы. Для этого в процедуре (PersonImpl) перед процедурой удаления пользователя, напишем следующее:
    @RolesAllowed("ROLE_ADMIN")
    public boolean delete(Person pers)

    Также отобразим имя вошедшего пользователя.
    Для начала создадим компоненты Label с id = «labelLogin», который будет служить для отображения имени пользователя и Toolbarbutton, который будет служить нам кнопкой выхода пользователя. В файле index.zul перед строкой <listbox id="lbPerson" hflex="1" vflex="1" checkmark="true", добавим следующее:
           <toolbar>
    	     <label id="labelLogin"/>
    	     /
                 <toolbarbutton label="Выход" href="/j_spring_security_logout"/>
           </toolbar>
    

    Ну и в классе PersonInfo внутри метода public void onCreate() реализуем возможность вывода имени пользователя:
    UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    ((Label) this.getFellow("labelLogin")).setValue(userDetails.getUsername());
    

    В данном коде мы получаем все данные пользователя, которые содержатся в UserDetails и компонент Label с id = «labelLogin» из формы index.zul, в который мы передадим имя пользователя.
    Теперь, запустив наше приложении, по адресу
    http://localhost:port/NameOfProject
    мы увидим, что автоматом нас перенаправили на страницу login.jsp.
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.