Всем доброго времени суток. Как и обещал, попытаюсь осветить тему секьюрности в веб-приложении, написанном на ZK Framework. Почему часть первая? Потому что в данной статье я покажу вам наиболее быстрый и простой метод внедрения Spring Security с использованием в качестве страницы авторизации- jsp страницу; в последующей(их) статье(ях) будут описаны более сложные и интересные методы с использованием zul в качестве построения страницы авторизации.
Веб-приложение писать с нуля не будем, а за основу возьмем мое прошлое приложение, которое я описывал в этом топике.
Что нам понадобится:
Данный метод можно реализовывать тоже по-разному, либо хранить юзеров, их пароли и права в xml конфигурации Spring Security, либо хранить в базе данных. Так как наше приложение и так работает с базой Oracle, так чего бы и юзеров не хранить в базе. Как говорит нам документация спринга, при дефолтном развертывании Spring Security смотрит в базу на 2 таблицы (users и authorities). При групповой политики, требуется наличие еще и таких таблиц, как :groups, group_authorities, group_members (скрипты таблиц можно взять отсюда).
Значит создаем в базе 2 таблицы вида:
Следующим шагом сконфигурируем наш Spring Security. В файл spring-config.xml внесем следующие изменения
Остановлюсь на некоторых моментах:
Также не забудем добавить в web.xml:
Все, с конфигурацией покончено. Теперь напишем страничку авторизации login.jsp.
Можно запускать и смотреть на наши плоды.
Давайте теперь поиграемся с разграничением прав. К примеру, разрешим только пользователю с правами ROLE_ADMIN, удалять пользователей из системы. Для этого в процедуре (PersonImpl) перед процедурой удаления пользователя, напишем следующее:
Также отобразим имя вошедшего пользователя.
Для начала создадим компоненты Label с id = «labelLogin», который будет служить для отображения имени пользователя и Toolbarbutton, который будет служить нам кнопкой выхода пользователя. В файле index.zul перед строкой
Ну и в классе PersonInfo внутри метода public void onCreate() реализуем возможность вывода имени пользователя:
В данном коде мы получаем все данные пользователя, которые содержатся в UserDetails и компонент Label с id = «labelLogin» из формы index.zul, в который мы передадим имя пользователя.
Теперь, запустив наше приложении, по адресу
Веб-приложение писать с нуля не будем, а за основу возьмем мое прошлое приложение, которое я описывал в этом топике.
Что нам понадобится:
- библиотеки самой Spring Security, которые возьмем отсюда
- библиотеку zk-spring-security
- jstl, которую берем с сайта
Данный метод можно реализовывать тоже по-разному, либо хранить юзеров, их пароли и права в 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— дает нам возможность использовать аннотации вида @RolesAllowed(«ROLE_ADMIN»), для группы прав данная строка будет иметь вид @RolesAllowed({«ROLE_ADMIN»,«ROLE_USER»});
secured-annotations="enabled" jsr250-annotations="enabled" /><security:intercept-url pattern="/login.jsp"— говорим, что все могут заходить на страницу login.jsp;
access="IS_AUTHENTICATED_ANONYMOUSLY" /><security:intercept-url pattern="/**"— только пользователи, которые имеют права ROLE_ADMIN и/или ROLE_USER могут заходить на все страницы
access="ROLE_ADMIN,ROLE_USER" /><security:form-login login-page="/login.jsp"— при правильном логине/пароле переходим на страницу index.zul (конечно если права у данного пользователя позволяют это сделать), в противном случае выводим код ошибки.
default-target-url="/index.zul" always-use-default-target="true"
authentication-failure-url="/login.jsp?login_error=1" />
Также не забудем добавить в 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, в который мы передадим имя пользователя.
Теперь, запустив наше приложении, по адресу
мы увидим, что автоматом нас перенаправили на страницу login.jsp.http://localhost:port/NameOfProject