Exemple d'annotation Spring Security + Hibernate
Dans ce didacticiel, l'exemple précédent deSpring Security + Hibernate4 XML sera réutilisé et converti en un exemple basé sur des annotations.
Technologies utilisées:
-
Spring 3.2.8.RELEASE
-
Spring Security 3.2.3.RELEASE
-
Hibernate 4.2.11.Final
-
MySQL Server 5.6
-
Tomcat 7 (conteneur Servlet 3.x)
Note rapide :
-
Créer une fabrique de session avec
LocalSessionFactoryBuilder
-
Injecter la fabrique de sessions dans un UserDao
-
Intégrez UserDao dans un
UserDetailsService
personnalisé, pour charger les utilisateurs depuis la base de données.
1. Répertoire des projets
Une structure de répertoire de projet final.
2. Modèle utilisateur + fichier de mappage
Classes de modèle et son fichier de mappage basé sur des annotations.
User.java
package com.example.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 SetuserRole = new HashSet (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) { 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 getUserRole() { return this.userRole; } public void setUserRole(Set userRole) { this.userRole = userRole; } }
UserRole.java
package com.example.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; } }
3. Classe DAO
Classes DAO, pour charger les données de la base de données, via Hibernate.
UserDao.java
package com.example.users.dao; import com.example.users.model.User; public interface UserDao { User findByUserName(String username); }
UserDaoImpl.java
package com.example.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.example.users.model.User; @Repository public class UserDaoImpl implements UserDao { @Autowired private SessionFactory sessionFactory; @SuppressWarnings("unchecked") public User findByUserName(String username) { Listusers = new ArrayList (); 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
Utilise@Transactional
pour déclarer une méthode transactionnelle.
MyUserDetailsService.java
package com.example.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.example.users.dao.UserDao; import com.example.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.example.users.model.User user = userDao.findByUserName(username); Listauthorities = buildUserAuthority(user.getUserRole()); return buildUserForAuthentication(user, authorities); } // Converts com.example.users.model.User user to // org.springframework.security.core.userdetails.User private User buildUserForAuthentication(com.example.users.model.User user, List authorities) { return new User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities); } private List buildUserAuthority(Set userRoles) { Set setAuths = new HashSet (); // Build user's authorities for (UserRole userRole : userRoles) { setAuths.add(new SimpleGrantedAuthority(userRole.getRole())); } List Result = new ArrayList (setAuths); return Result; } }
5. Annotation de sécurité du printemps
Déclare et lie tout avec des annotations, lisez les commentaires, cela devrait être explicite.
SecurityConfig.java
package com.example.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; } }
UtiliseLocalSessionFactoryBuilder
pour créer une fabrique de session.
AppConfig.java
package com.example.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.example.*" }) @EnableTransactionManagement @Import({ SecurityConfig.class }) public class AppConfig { @Bean public SessionFactory sessionFactory() { LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource()); builder.scanPackages("com.example.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; } }
Terminé.
6. Démo du projet
La démo vidéo suivante est pour le didacticielSpring Security database login. Étant donné que ce didacticiel génère la même sortie, la démonstration vidéo est donc réutilisée.
6.1 Access a password protected page : http://localhost:8080/spring-security-hibernate-annotation/admin , a login page is displayed.
6.2 Enter user “example” and password “123456”.
6.3 Try access /admin
page with user “alex” and password “123456”, a 403 page will be displayed.
Télécharger le code source
Téléchargez-le -spring-security-hibernate-annotation.zip (35 Ko)