春のセキュリティ+休止状態の注釈の例

Spring Security + Hibernate Annotationの例

spring-hibernate-logo

このチュートリアルでは、前のSpring Security + Hibernate4 XMLの例を再利用し、注釈ベースの例に変換します。

使用される技術:

  1. Spring 3.2.8.RELEASE

  2. Spring Security 3.2.3.RELEASE

  3. Hibernate 4.2.11。最終

  4. MySQLサーバー5.6

  5. Tomcat 7(サーブレット3.xコンテナー)

クイックノート:

  1. LocalSessionFactoryBuilderを使用してセッションファクトリを作成します

  2. セッションファクトリをUserDaoに挿入する

  3. UserDaoをカスタムUserDetailsServiceに統合して、データベースからユーザーをロードします。

1. プロジェクトディレクトリ

最終的なプロジェクトディレクトリ構造。

spring-security-hibernate-annotation-directory

2. ユーザーモデル+マッピングファイル

モデルクラスとその注釈ベースのマッピングファイル。

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 Set userRole = 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. DAOクラス

DAOクラス。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) {

        List users = 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. UserDetailsS​​ervice

@Transactionalを使用してトランザクションメソッドを宣言します。

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);
        List authorities =
                                      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. Spring Securityアノテーション

すべてをアノテーションで宣言してバインドし、コメントを読みます。それは一目瞭然です。

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;
    }

}

LocalSessionFactoryBuilderを使用してセッションファクトリを作成します。

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;
    }

}

完了しました。

6. プロジェクトのデモ

次のビデオデモは、Spring Security database loginチュートリアル用です。 このチュートリアルでは同じ出力が生成されるため、ビデオデモは再利用されます。

6.1 Access a password protected page : http://localhost:8080/spring-security-hibernate-annotation/admin , a login page is displayed.

spring-security-hibernate-annotation1

6.2 Enter user “example” and password “123456”.

spring-security-hibernate-annotation2

6.3 Try access /admin page with user “alex” and password “123456”, a 403 page will be displayed.

spring-security-hibernate-annotation3

ソースコードをダウンロード

ダウンロード–spring-security-hibernate-annotation.zip(35 KB)