このチュートリアルでは、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]