Статьи

Spring Security Part 1 — Простое приложение для входа в систему с базой данных

Что такое Spring Security?

Spring security — это инфраструктура, которая обеспечивает решение безопасности, обрабатывая аутентификацию и авторизацию как на уровне веб-запросов, так и на уровне методов. Пружина безопасности обрабатывает безопасность двумя способами. Один — это безопасный веб-запрос, а другой — ограничение доступа на уровне URL. Spring Security использует фильтры сервлетов.

В этом посте я собираюсь создать простое веб-приложение, которое обрабатывает аутентификацию и авторизацию при входе в систему.

Загрузить проект: http://www.mediafire.com/?bb9x88uxvkb0uuv или http://dl.dropbox.com/u/7215751/JavaCodeGeeks/SpringSecurityTutorialPart1/spring-security-login-example.rar

Перед созданием проекта необходимо выполнить несколько запросов к mysql, чтобы создать новую базу данных, таблицы и добавить некоторые примеры данных.

создание-table.sql

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
CREATE DATABASE IF NOT EXISTS `spring-test`; 
-- create user 
CREATE USER 'user'@'localhost' IDENTIFIED BY 'test'
GRANT ALL ON spring-test.* TO 'user'@'localhost'
USE `spring-test`; 
CREATE TABLE USER_DETAILS ( 
USERNAME VARCHAR(10) NOT NULL, 
PASSWORD VARCHAR(32) NOT NULL, 
PRIMARY KEY (USERNAME) 
); 
CREATE TABLE USER_AUTH ( 
USERNAME VARCHAR(10) NOT NULL, 
AUTHORITY VARCHAR(10) NOT NULL, 
FOREIGN KEY (USERNAME) REFERENCES USER_DETAILS(USERNAME) 
);

Тест-data.sql

1
2
3
4
insert into USER_DETAILS values ('user','123'); 
insert into USER_DETAILS values ('admin','admin'); 
insert into USER_AUTH values ('user', 'ROLE_USER'); 
insert into USER_AUTH values ('admin', 'ROLE_ADMIN');

После этого я создаю веб-проект, используя maven, и добавляю следующие зависимости в pom.xml.

1
2
3
<properties>
        <spring.version>3.0.5.RELEASE</spring.version>
</properties>
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<dependencies
     <dependency
       <groupId>javax.validation</groupId
       <artifactId>validation-api</artifactId
       <version>1.0.0.GA</version
     </dependency
     <dependency
       <groupId>org.springframework</groupId
       <artifactId>spring-core</artifactId
       <version>${spring.version}</version
     </dependency
     <dependency
       <groupId>org.springframework</groupId
       <artifactId>spring-web</artifactId
       <version>${spring.version}</version
     </dependency
     <dependency
       <groupId>org.springframework</groupId
       <artifactId>spring-webmvc</artifactId
       <version>${spring.version}</version
     </dependency
     <dependency
       <groupId>org.springframework</groupId
       <artifactId>spring-jdbc</artifactId
       <version>${spring.version}</version
     </dependency
     <!-- Spring Security --> 
     <dependency
       <groupId>org.springframework.security</groupId
       <artifactId>spring-security-core</artifactId
       <version>${spring.version}</version
     </dependency
     <dependency
       <groupId>org.springframework.security</groupId
       <artifactId>spring-security-web</artifactId
       <version>${spring.version}</version
     </dependency
     <dependency
       <groupId>org.springframework.security</groupId
       <artifactId>spring-security-config</artifactId
       <version>${spring.version}</version
     </dependency
     <dependency
       <groupId>org.springframework.security</groupId
       <artifactId>spring-security-taglibs</artifactId
       <version>${spring.version}</version
     </dependency
     <dependency
       <groupId>org.springframework.security</groupId
       <artifactId>spring-security-acl</artifactId
       <version>${spring.version}</version
     </dependency
     <!-- jstl --> 
     <dependency
       <groupId>javax.servlet</groupId
       <artifactId>jstl</artifactId
       <version>1.2</version
     </dependency
     <!-- MySQL database driver --> 
     <dependency
       <groupId>mysql</groupId
       <artifactId>mysql-connector-java</artifactId
       <version>5.1.9</version
     </dependency
     <dependency
       <groupId>c3p0</groupId
       <artifactId>c3p0</artifactId
       <version>0.9.1</version
     </dependency
   </dependencies>

После этого измените web.xml следующим образом

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE web-app PUBLIC 
    '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN' 
<web-app
  <display-name>spring-security-login</display-name
  <servlet
    <servlet-name>login</servlet-name
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class
    <load-on-startup>1</load-on-startup
  </servlet
  <servlet-mapping
    <servlet-name>login</servlet-name
    <url-pattern>/</url-pattern
  </servlet-mapping
  <listener
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class
  </listener
  <context-param
    <param-name>contextConfigLocation</param-name
    <param-value
      /WEB-INF/login-servlet.xml, 
      /WEB-INF/login-security.xml, 
      /WEB-INF/login-service.xml 
    </param-value
  </context-param
  <!-- Spring Security --> 
  <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
  <welcome-file-list
    <welcome-file>login.jsp</welcome-file
  </welcome-file-list
</web-app>

Теперь мне нужно создать конфигурационные файлы login-servlet.xml, login-security.xml и login-service.xml. В этом примере мы используем пул соединений c3p0 с базой данных Mysql.

Вот файл login-servlet.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version='1.0' encoding='UTF-8'?> 
    xsi:schemaLocation=' 
  <context:component-scan base-package='rd.controller'/> 
  <bean id='internalResourceResolver' 
     class='org.springframework.web.servlet.view.InternalResourceViewResolver'
    <property name='prefix' value='/WEB-INF/views/'/> 
    <property name='suffix' value='.jsp'/> 
  </bean
  <bean class='org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping'></bean
  <bean class='org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter'/> 
  <bean id='placeholderConfig' 
     class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'
    <property name='locations'
      <list
        <value>classpath:login.properties</value
      </list
    </property
  </bean
</beans>

Вот логин-security.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version='1.0' encoding='UTF-8'?> 
       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 
  <beans:import resource='login-service.xml'/> 
  <http
    <intercept-url pattern='/home*' access='ROLE_USER,ROLE_ADMIN' /> 
    <intercept-url pattern='/admin*' access='ROLE_ADMIN' /> 
    <form-login login-page='/login.jsp' default-target-url='/home' authentication-failure-url='/login.jsp?error=true'/> 
    <logout logout-success-url='/login.jsp' /> 
    <anonymous username='guest' granted-authority='ROLE_GUEST'/> 
    <remember-me/> 
  </http
  <authentication-manager
    <authentication-provider
      <!--<user-service>--> 
        <!--<user name='admin' password='secret' authorities='ROLE_ADMIN,ROLE_USER' />--> 
        <!--<user name='user1' password='1111' authorities='ROLE_USER' />--> 
      <!--</user-service>--> 
      <jdbc-user-service data-source-ref='dataSource' 
          users-by-username-query='select username,password, 'true' as enabled from USER_DETAILS where username=?' 
          authorities-by-username-query='select USER_DETAILS.username , USER_AUTH.AUTHORITY as authorities from USER_DETAILS,USER_AUTH 
           where USER_DETAILS.username = ? AND USER_DETAILS.username=USER_AUTH.USERNAME '/> 
    </authentication-provider
  </authentication-manager
</beans:beans>

Вот логин-сервис.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  <bean id='dataSource' class='com.mchange.v2.c3p0.ComboPooledDataSource'
    <!--Driver name to connect to the database--> 
    <property name='driverClass'
      <value>${login.jdbc.driver}</value
    </property
    <!--DB URL--> 
    <property name='jdbcUrl'
      <value>${login.url}</value
    </property
    <!--DB User used to connect to the schema--> 
    <property name='user'
      <value>${login.username}</value
    </property
    <!--Password required to access for the above user--> 
    <property name='password'
      <value>${login.password}</value
    </property
    <!-- configuration pool via c3p0--> 
    <property name='acquireIncrement'
      <value>${login.c3p0.acquireIncrement}</value
    </property
    <property name='idleConnectionTestPeriod'
      <value>${login.c3p0.idleConnectionTestPeriod}</value
      <!-- seconds --> 
    </property
    <property name='maxPoolSize'
      <value>${login.c3p0.maxPoolSize}</value
    </property
    <property name='maxStatements'
      <value>${login.c3p0.maxStatements}</value
    </property
    <property name='minPoolSize'
      <value>${login.c3p0.minPoolSize}</value
    </property
    <property name='initialPoolSize'
      <value>${login.c3p0.initialPoolSize}</value
    </property
    <property name='maxIdleTime'
      <value>${login.c3p0.maxIdleTime}</value
    </property
    <property name='acquireRetryAttempts'
      <value>${login.c3p0.acquireRetryAttempts}</value
    </property
    <property name='acquireRetryDelay'
      <value>${login.c3p0.acquireRetryDelay}</value
    </property
    <property name='breakAfterAcquireFailure'
      <value>${login.c3p0.breakAfterAcquireFailure}</value
    </property
  </bean
</beans>

Страница login.jsp выглядит следующим образом. (Необходимо разместить в каталоге веб-приложения. Но не в каталоге WEB_INF)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> 
<html
<head
  <title>Login</title
</head
<body
<c:if test='${not empty param.error}'
  <font color='red'
    Login error. <br /> 
    Reason : ${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message} 
  </font
</c:if
<form method='POST' action='<c:url value='/j_spring_security_check' />'> 
  <table
    <tr
      <td align='right'>Username</td
      <td><input type='text' name='j_username' /></td
    </tr
    <tr
      <td align='right'>Password</td
      <td><input type='password' name='j_password' /></td
    </tr
    <tr
      <td colspan='2' align='right'
        <input type='submit' value='Login' /> 
      </td
    </tr
  </table
</form
</body
</html>

страница home.jsp

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> 
<%@ taglib prefix='sec' uri='http://www.springframework.org/security/tags' %> 
<html
<head
  <title>Home</title
</head
<body
  <a href=<c:url value='/j_spring_security_logout'/>>Logout</a><br/> 
  <sec:authorize ifAnyGranted='ROLE_ADMIN'
    <h1>Only admin can see this</h1><br/> 
    <a href='admin'> Admin Home </a
  </sec:authorize
  <h1>Welcome</h1
</body
</html>

страница admin-home.jsp

01
02
03
04
05
06
07
08
09
10
11
<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> 
<%@ page contentType='text/html;charset=UTF-8' language='java' %> 
<html
<head
  <title>Admin</title
</head
<body
  <a href=<c:url value='/j_spring_security_logout'/>>Logout</a><br/> 
  <h1>Only Admin allowed here</h1
</body
</html>

После этого вам нужно написать два контроллера для извлечения домашней страницы и административной домашней страницы. Вот HomeController.java

01
02
03
04
05
06
07
08
09
10
11
12
package rd.controller; 
import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 
@Controller 
public class HomeController { 
  @RequestMapping(value = '/home' , method = RequestMethod.GET) 
  public String setUp(Model model){ 
    return 'home'
  
}

Вот AdminController.java

01
02
03
04
05
06
07
08
09
10
11
12
package rd.controller; 
import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 
@Controller 
public class AdminController { 
  @RequestMapping(value = '/admin' , method = RequestMethod.GET) 
  public String setUp(Model model){ 
    return 'admin-home'
  
}

Вот и все. Запустите команду mvn clean install для создания файла войны. Скопируйте файл war в каталог tomcat / webapps и получите доступ к веб-приложению в своем любимом браузере.
url: localhost: <порт> /spring-login/login.jsp

Контрольный пример 1: попробуйте войти в систему с именем пользователя 123 в качестве пароля. Вы получите домашнюю страницу пользователей.
Тестовый пример 2: Попробуйте войти с помощью admin как имя пользователя admin в качестве пароля. Вы получите домашнюю страницу пользователя с видимой ссылкой на страницу администратора.

В весенней безопасности, часть 2, я изменю этот проект и добавлю функцию запомнить меня и функцию шифрования пароля md5.

В ближайшем будущем я попытаюсь опубликовать интересную статью о весенней безопасности с интеграцией CAS и LDAP. Оставайтесь в курсе 🙂

Ссылка: Spring Security Part 1 — Простое приложение для входа в систему с базой данных от нашего партнера по JCG Раджита Деланта в блоге Looping with Rajith… .