SpringセキュリティHibernate XMLの例

このチュートリアルでは、Hibernate 4をSpring Security、XMLの設定例に統合する方法について説明します。
使用される技術:
-
Spring 3.2.8.RELEASE
-
春のセキュリティ3.2.3.RELEASE
-
Hibernate 4.2.11.最終
-
MySQLサーバ5.6
-
JDK 1.6
-
Maven 3
-
Eclipse 4.3
クイックノート
-
`hibernate4.LocalSessionFactoryBean`でセッションファクトリを作成します.
-
セッションファクトリをUserDaoに注入する
-
Spring Securityと統合するには、そのクラスを実装するクラスを作成します.
`UserDetailsService`インターフェースを呼び出し、UserDaoでUserを読み込みます
。トランザクションマネージャが宣言されていなければなりません。そうでなければ、Hibernateは動作しません
春
1.プロジェクトディレクトリ
最終的なプロジェクトディレクトリ構造。

プロジェクトの依存関係
POMファイル内のプロジェクトの依存関係のリスト。
pom.xml
<properties>
<spring.version>3.2.8.RELEASE</spring.version>
<spring.security.version>3.2.3.RELEASE</spring.security.version>
<jstl.version>1.2</jstl.version>
<mysql.connector.version>5.1.30</mysql.connector.version>
<logback.version>1.1.2</logback.version>
<slf4j.version>1.7.6</slf4j.version>
<hibernate.version>4.2.11.Final</hibernate.version>
<dbcp.version>1.4</dbcp.version>
<servletapi.version>2.5</servletapi.version>
</properties>
<dependencies>
<!-- database pool -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>${dbcp.version}</version>
</dependency>
<!-- Hibernate ORM -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- Spring 3 dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring + aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- ORM integration, e.g Hibernate -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<!-- Spring Security JSP Taglib -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<!-- jstl for jsp page -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<!-- MySql Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.version}</version>
</dependency>
<!-- logging, slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servletapi.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
3.ユーザーテーブル
ユーザーとユーザーの役割を格納するテーブルを作成するSQLスクリプト。
mysql.sql
CREATE TABLE users (
username VARCHAR(45) NOT NULL ,
password VARCHAR(60) NOT NULL ,
enabled TINYINT NOT NULL DEFAULT 1 ,
PRIMARY KEY (username));
CREATE TABLE user__roles (
user__role__id int(11) NOT NULL AUTO__INCREMENT,
username varchar(45) NOT NULL,
role varchar(45) NOT NULL,
PRIMARY KEY (user__role__id),
UNIQUE KEY uni__username__role (role,username),
KEY fk__username__idx (username),
CONSTRAINT fk__username FOREIGN KEY (username) REFERENCES users (username));
INSERT INTO users(username,password,enabled)
VALUES ('mkyong','$2a$10$04TVADrR6/SPLBjsK0N30.Jf5fNjBugSACeGv1S69dZALR7lSov0y', true);
INSERT INTO users(username,password,enabled)
VALUES ('alex','$2a$10$04TVADrR6/SPLBjsK0N30.Jf5fNjBugSACeGv1S69dZALR7lSov0y', true);
INSERT INTO user__roles (username, role)
VALUES ('mkyong', 'ROLE__USER');
INSERT INTO user__roles (username, role)
VALUES ('mkyong', 'ROLE__ADMIN');
INSERT INTO user__roles (username, role)
VALUES ('alex', 'ROLE__USER');
4.ユーザモデルのHibernate XMLマッピング
モデルクラスとその ‘XMLマッピングファイル。
User.java
package com.mkyong.users.model;
import java.util.HashSet;
import java.util.Set;
public class User {
private String username;
private String password;
private boolean enabled;
private Set<UserRole> userRole = new HashSet<UserRole>(0);
//getter and setter methods
}
UserRole.java
package com.mkyong.users.model;
public class UserRole{
private Integer userRoleId;
private User user;
private String role;
//getter and setter methods
}
Users.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.mkyong.users.model.User" table="users" catalog="test">
<id name="username" type="string">
<column name="username" length="45"/>
<generator class="assigned"/>
</id>
<property name="password" type="string">
<column name="password" length="60" not-null="true"/>
</property>
<property name="enabled" type="boolean">
<column name="enabled" not-null="true"/>
</property>
<set name="userRole" table="user__roles" inverse="true" lazy="true" fetch="select">
<key>
<column name="username" length="45" not-null="true"/>
</key>
<one-to-many class="com.mkyong.users.model.UserRole"/>
</set>
</class>
</hibernate-mapping>
UserRoles.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.mkyong.users.model.UserRole" table="user__roles" catalog="test">
<id name="userRoleId" type="java.lang.Integer">
<column name="user__role__id"/>
<generator class="identity"/>
</id>
<many-to-one name="user" class="com.mkyong.users.model.User" fetch="select">
<column name="username" length="45" not-null="true"/>
</many-to-one>
<property name="role" type="string">
<column name="role" length="45" not-null="true"/>
</property>
</class>
</hibernate-mapping>
5. DAOクラス
Hibernateを介してデータベースからユーザをロードするための `UserDao`クラスを作成します。
UserDao.java
package com.mkyong.users.dao;
import com.mkyong.users.model.User;
public interface UserDao {
User findByUserName(String username);
}
UserDaoImpl.java
package com.mkyong.users.dao;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.SessionFactory;
import com.mkyong.users.model.User;
public class UserDaoImpl implements UserDao {
private SessionFactory sessionFactory;
@SuppressWarnings("unchecked")
public User findByUserName(String username) {
List<User> users = new ArrayList<User>();
users = getSessionFactory().getCurrentSession()
.createQuery("from User where username=?")
.setParameter(0, username).list();
if (users.size() > 0) {
return users.get(0);
} else {
return null;
}
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
6. UserDetailsService
カスタム
UserDetailsService`を作成し、
UserDao`からユーザーをロードし、ユーザーの権限を作成します。
-
注意** 例はこのSpringのリンクからの参照です:org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl[JdbcDaoImpl]
MyUserDetailsService.java
package com.mkyong.users.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.mkyong.users.dao.UserDao;
import com.mkyong.users.model.UserRole;
public class MyUserDetailsService implements UserDetailsService {
private UserDao userDao;
@Override
public UserDetails loadUserByUsername(final String username)
throws UsernameNotFoundException {
com.mkyong.users.model.User user = userDao.findByUserName(username);
List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRole());
return buildUserForAuthentication(user, authorities);
}
//Converts com.mkyong.users.model.User user to
//org.springframework.security.core.userdetails.User
private User buildUserForAuthentication(com.mkyong.users.model.User user,
List<GrantedAuthority> authorities) {
return new User(user.getUsername(),
user.getPassword(), user.isEnabled(),
true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
//Build user's authorities
for (UserRole userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
7.春のセキュリティXML
コメントを読んで、それは自明であるべきです。
spring-security.xml
<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.2.xsd">
<!-- enable use-expressions -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin** ** " access="hasRole('ROLE__ADMIN')"/>
<!-- access denied page -->
<access-denied-handler error-page="/403"/>
<form-login
login-page="/login"
default-target-url="/welcome"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password"/>
<logout logout-success-url="/login?logout"/>
<!-- enable csrf protection -->
<csrf/>
</http>
<authentication-manager>
<authentication-provider user-service-ref="myUserDetailsService" >
<password-encoder hash="bcrypt"/>
</authentication-provider>
</authentication-manager>
</beans:beans>
spring-database.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
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.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- MySQL data source -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<!-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>orm/Users.hbm.xml</value>
<value>orm/UserRoles.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQL5Dialect
</prop>
<prop key="hibernate.format__sql">true</prop>
<prop key="hibernate.show__sql">true</prop>
</props>
</property>
</bean>
<bean id="userDao" class="com.mkyong.users.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="myUserDetailsService"
class="com.mkyong.users.service.MyUserDetailsService">
<property name="userDao" ref="userDao"/>
</bean>
<!-- MUST have transaction manager, using aop and aspects -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get** " read-only="true"/>
<tx:method name="find** " read-only="true"/>
<tx:method name="** "/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="userServicePointCut"
expression="execution(** com.mkyong.users.service.** Service.** (..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="userServicePointCut"/>
</aop:config>
</beans>
完了しました。
-
注意** これらのJSP、web.xml、コントローラファイルは省略されていますが、それはかなり標準的なコードです。興味があれば、記事の末尾にある完全なソースコードをダウンロードしてください。
8.プロジェクトデモ
次のビデオデモは、//spring-security/spring-security-form-login-using-database/[Springセキュリティデータベースログインwith JDBC]チュートリアルのリンクです。このチュートリアルでは同じ出力を生成していますが、Hibernateを使用してユーザーをロードするので、ビデオデモが再利用されるためです。
8.1パスワードで保護されたページにアクセスする:

8.2ユーザ “mkyong”とパスワード “123456”を入力します。

8.3ユーザー “alex”とパスワード “123456”で `/admin`ページにアクセスしようとすると、403ページが表示されます。

ソースコードをダウンロードする
ダウンロードする –
spring-security-hibernate.zip
(30 KB)
参考文献
ORM – 休止状態]。
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/orm/hibernate4/LocalSessionFactoryBean.html
[Spring
Hibernate4 LocalSessionFactoryBean JavaDoc]。
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/orm/hibernate3/LocalSessionFactoryBean.html
[Spring
Hibernate3 LocalSessionFactoryBean JavaDoc]。
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/htmlsingle/#transaction
[Spring
トランザクション管理]。
Hibernate ORM documentation
-
リンク://spring-security/spring-security-form-login-using-database/[Spring
データベースを使用したセキュリティフォームのログイン、JDBC付き]。リンク://spring/spring-hibernate-no-session-found-for-current-thread/[Hibernate
: No Session Found For Current Thread]