Всем доброго времени суток. Как и обещал, попытаюсь осветить тему секьюрности в веб-приложении, написанном на 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, в который мы передадим имя пользователя.
Теперь, запустив наше приложении, по адресу
http://localhost:port/NameOfProject
мы увидим, что автоматом нас перенаправили на страницу login.jsp.