春のセキュリティ+休止状態の注釈の例
このチュートリアルでは、以前のリンク://spring-security/spring-security-hibernate-xml-example/[Spring Security + Hibernate4 XML]の例を再利用して、アノテーションベースの例に変換します。
使用される技術:
-
Spring 3.2.8.RELEASE
-
春のセキュリティ3.2.3.RELEASE
-
Hibernate 4.2.11.最終
-
MySQLサーバ5.6
-
Tomcat 7(サーブレット3.xコンテナ)
クイックノート:
-
`LocalSessionFactoryBuilder`を使ってセッションファクトリを作成する
-
セッションファクトリをUserDaoに注入する
-
ユーザをロードするために、カスタム `UserDetailsService`にUserDaoを統合する
データベースから。
1.プロジェクトディレクトリ
最終的なプロジェクトディレクトリ構造。
2.ユーザーモデル+マッピングファイル
モデルクラスとそのアノテーションベースのマッピングファイル
User.java
package com.mkyong.users.model; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "users", catalog = "test") public class User { private String username; private String password; private boolean enabled; private Set<UserRole> userRole = new HashSet<UserRole>(0); public User() { } public User(String username, String password, boolean enabled) { this.username = username; this.password = password; this.enabled = enabled; } public User(String username, String password, boolean enabled, Set<UserRole> userRole) { this.username = username; this.password = password; this.enabled = enabled; this.userRole = userRole; } @Id @Column(name = "username", unique = true, nullable = false, length = 45) public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; } @Column(name = "password", nullable = false, length = 60) public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; } @Column(name = "enabled", nullable = false) public boolean isEnabled() { return this.enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } @OneToMany(fetch = FetchType.LAZY, mappedBy = "user") public Set<UserRole> getUserRole() { return this.userRole; } public void setUserRole(Set<UserRole> userRole) { this.userRole = userRole; } }
UserRole.java
package com.mkyong.users.model; import static javax.persistence.GenerationType.IDENTITY; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.persistence.UniqueConstraint; @Entity @Table(name = "user__roles", catalog = "test", uniqueConstraints = @UniqueConstraint( columnNames = { "role", "username" })) public class UserRole{ private Integer userRoleId; private User user; private String role; public UserRole() { } public UserRole(User user, String role) { this.user = user; this.role = role; } @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "user__role__id", unique = true, nullable = false) public Integer getUserRoleId() { return this.userRoleId; } public void setUserRoleId(Integer userRoleId) { this.userRoleId = userRoleId; } @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "username", nullable = false) public User getUser() { return this.user; } public void setUser(User user) { this.user = user; } @Column(name = "role", nullable = false, length = 45) public String getRole() { return this.role; } public void setRole(String role) { this.role = role; } }
DAOクラス
DAOクラスを使用して、Hibernateを介してデータベースからデータをロードします。
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 org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import com.mkyong.users.model.User; @Repository public class UserDaoImpl implements UserDao { @Autowired private SessionFactory sessionFactory; @SuppressWarnings("unchecked") public User findByUserName(String username) { List<User> users = new ArrayList<User>(); users = sessionFactory.getCurrentSession() .createQuery("from User where username=?") .setParameter(0, username) .list(); if (users.size() > 0) { return users.get(0); } else { return null; } } }
4. UserDetailsService
`@ Transactional`を使ってトランザクションメソッドを宣言します。
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.beans.factory.annotation.Autowired; 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 org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.mkyong.users.dao.UserDao; import com.mkyong.users.model.UserRole; @Service("userDetailsService") public class MyUserDetailsService implements UserDetailsService { //get user from the database, via Hibernate @Autowired private UserDao userDao; @Transactional(readOnly=true) @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; } }
5.春のセキュリティ注釈
注釈ですべてを宣言してバインドし、コメントを読んで、それは自明でなければなりません。
SecurityConfig.java
package com.mkyong.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("userDetailsService") UserDetailsService userDetailsService; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/admin/** ** ") .access("hasRole('ROLE__ADMIN')").and().formLogin() .loginPage("/login").failureUrl("/login?error") .usernameParameter("username") .passwordParameter("password") .and().logout().logoutSuccessUrl("/login?logout") .and().csrf() .and().exceptionHandling().accessDeniedPage("/403"); } @Bean public PasswordEncoder passwordEncoder(){ PasswordEncoder encoder = new BCryptPasswordEncoder(); return encoder; } }
`LocalSessionFactoryBuilder`を使用してセッションファクトリを作成します。
AppConfig.java
package com.mkyong.config; import java.util.Properties; import org.apache.commons.dbcp.BasicDataSource; import org.hibernate.SessionFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.orm.hibernate4.HibernateTransactionManager; import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @EnableWebMvc @Configuration @ComponentScan({ "com.mkyong.** " }) @EnableTransactionManagement @Import({ SecurityConfig.class }) public class AppConfig { @Bean public SessionFactory sessionFactory() { LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource()); builder.scanPackages("com.mkyong.users.model") .addProperties(getHibernateProperties()); return builder.buildSessionFactory(); } private Properties getHibernateProperties() { Properties prop = new Properties(); prop.put("hibernate.format__sql", "true"); prop.put("hibernate.show__sql", "true"); prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect"); return prop; } @Bean(name = "dataSource") public BasicDataSource dataSource() { BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/test"); ds.setUsername("root"); return ds; } //Create a transaction manager @Bean public HibernateTransactionManager txManager() { return new HibernateTransactionManager(sessionFactory()); } @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/pages/"); viewResolver.setSuffix(".jsp"); return viewResolver; } }
完了しました。
6.プロジェクトデモ
以下のビデオデモは、//spring-security/spring-security-form-login-using-database/[Spring Security database login]チュートリアルのリンクです。このチュートリアルでは同じ出力が生成されているので、ビデオデモは再利用されています。
6.1パスワードで保護されたページにアクセスする:
http://localhost:8080/spring-security-hibernate-annotation/admin
、ログインページが表示されます。
6.2ユーザー “mkyong”とパスワード “123456”を入力します。
6.3ユーザー “alex”とパスワード “123456”で `/admin`ページにアクセスしようとすると、403ページが表示されます。
ソースコードをダウンロードする
ダウンロードする – リンク://wp-content/uploads/2014/05/spring-security-hibernate-annotation.zip[spring-security-hibernate-annotation.zip](35 KB)
参考文献
-
リンク://spring-security/spring-security-hibernate-xml-example/[Spring
セキュリティ+ Hibernate XMLの例]。リンク://spring-security/spring-security-hello-world-annotation-example/[Spring
セキュリティHello Worldの注釈の例]。
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/orm/hibernate4/LocalSessionFactoryBuilder.html
[LocalSessionFactoryBuilder
JavaDoc]。
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/htmlsingle/#orm-hibernate
[Spring
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/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]