12月3日

ログアウトの設定

ログアウトを実行したい場合、spring-security.xml に以下の設定をする。

<sec:http auto-config="true">
    <intercept-url pattern="/**" access="ROLE_USER" />
    <sec:form-login login-page="/login.jsp"
        default-target-url="/home"
        authentication-failure-handler-ref="authenticationFailureHandler" />
    <sec:logout
        logout-url="/logout"
        logout-success-url="/"
        invalidate-session="true"
        delete-cookies="JSESSIONID" />
</sec:http>
 
<beans:bean id="authenticationFailureHandler"
    class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
    <beans:property name="defaultFailureUrl" value="/login.jsp?error=true"/>
    <beans:property name="useForward" value="true"/>
</beans:bean>

ログインしたユーザー情報の取得

ログインしたユーザーを取得するには、コントローラの引数に Principal を追加する。
ここでは、追加した Princical から getName()メソッドでユーザー名を取得し、addAttribute() で name に値を設定している。

@RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Model model, Principal p) {
    model.addAttribute("name", p.getName());
    return "home";
}

Userインスタンスの取得

Principal から取得できるのは名前だけなので、詳細な情報を取得するには、名前をキーにしてUsersテーブルから取得する必要がある。
Usersテーブルから名前をキーにして取得するために、DAOにメソッド定義 findByName() を追加する。

UserDao.java

public interface UserDao<T> {
    public List<T> getAll();
    public T findById(long id);
    public T findByName(String name);
    public void add(T data);
    public void update(T data);
    public void delete(T data);
    public void delete(long id);
}

UserDaoImpl で、検索機能を実装する。

UserDaoImpl.java

public class UserDaoImpl implements UserDao<User> {
    private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("persistenceUnit");
 
    public List<User> getAll() {
        EntityManager manager = factory.createEntityManager();
        CriteriaBuilder builder = manager.getCriteriaBuilder();
        CriteriaQuery<User> query = builder.createQuery(User.class);
        Root<User> root = query.from(User.class);
        query.select(root);
        List<User> list = null;
        try {
            list = manager.createQuery(query).getResultList();
        } catch (NoResultException e) {
            //
        }
        return list;
    }
 
    public User findById(long id) {
        EntityManager manager = factory.createEntityManager();
        CriteriaBuilder builder = manager.getCriteriaBuilder();
        CriteriaQuery<User> query = builder.createQuery(User.class);
        Root<User> root = query.from(User.class);
        query.select(root).where(builder.equal(root.get("id"), id));
        User u = null;
        try {
            u = manager.createQuery(query).getSingleResult();
        } catch (NoResultException e) {
            //
        }
        return u;
    }
 
    public User findByName(String name) {
        EntityManager manager = factory.createEntityManager();
        CriteriaBuilder builder = manager.getCriteriaBuilder();
        CriteriaQuery<User> query = builder.createQuery(User.class);
        Root<User> root = query.from(User.class);
        query.select(root).where(builder.equal(root.get("name"), name));
        User u = null;
        try {
            u = manager.createQuery(query).getSingleResult();
        } catch (NoResultException e) {
            //
        }
        return u;
    }
 
    public void add(User user) {
        EntityManager manager = factory.createEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        User u = findById(user.getId());
        if (u == null) {
            try {
                manager.persist(user);
                transaction.commit();
            } catch (PersistenceException e) {
                transaction.rollback();
            }
            manager.close();
        } else {
            throw new PersistenceException("Duplicate user-id : " + u.getId());
        }
    }
 
    public void update(User user) {
        EntityManager manager = factory.createEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        try {
            manager.merge(user);
            transaction.commit();
        } catch (PersistenceException e) {
            transaction.rollback();
        }
        manager.close();
    }
 
    public void delete(User user) {
        EntityManager manager = factory.createEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        try {
            manager.remove(user);
            transaction.commit();
        } catch (PersistenceException e) {
            transaction.rollback();
        }
        manager.close();
    }
 
    public void delete(long id) {
        delete(findById(id));
    }
 
}

11月9日

機能の検討方法と課題の作り方

機能を検討するときは、必要最小限の機能を先に作る。
たとえば、編集や削除を行う場合に、編集内容や削除の確認があったほうがいいと思った場合、まずは確認を行わないUIを作成する。
課題は以下のように作成する。

  1. 編集画面の作成(JSP)
  2. 編集を受け付けるコントローラの実装
  3. 編集をDBに反映するDAOの実装

確認しないUIで作成して動かしてみる。
実際に使ってみて、確認が必要だと思ったら確認のUIを追加する。

  1. 編集確認のUI作成(JSP/JavaScript)
  2. 編集確認でOKでの実装
  3. 編集確認でキャンセル時の実装

11月5日

Spring Security によるログイン

pom.xml に以下の設定を追加する。
pom.xml

		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-core</artifactId>
		    <version>4.0.1.RELEASE</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-web</artifactId>
		    <version>4.0.1.RELEASE</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-config</artifactId>
		    <version>4.0.1.RELEASE</version>
		</dependency>

web.xml

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/application-config.xml</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/spring-security.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <!--
		- Servlet that dispatches request to registered handlers (Controller implementations).
	-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/mvc-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

10月29日

サービスのトップページを作ろう

デフォルトでは「Click to Enter」とだけ表示している画面を、独自のトップページに修正しよう。
修正するファイルは、webapp の下にある index.jsp 。

  • つぶやき6ヶ:未
  • harunoumi:未
  • kentomori:済
  • SESオールスターズ:未
  • 歪みねぇやぴ軍団:未

アクセスコントロール

Springでは、Spring Security によって、ログインなしでアクセスできるところと、ログインが必要なところを分類する。
ログインしていない状態でログインが必要なところにアクセスすると、自動的に標準のログインダイアログを表示する。
ログイン画面を標準のものと変えたいときは、spring-security.xml で、ログ引用のJSPを設定する。

10月5日

データベースを使用した認証

ユーザーとユーザの権限を管理するためのテーブルを作成する。

CREATE TABLE users(
 user_id bigint NOT NULL identity,
 user_name varchar(50) NOT NULL,
 password varchar(50) NOT NULL,
 enabled tinyint NOT NULL,
 role varchar(100) NOT NULL
);

テーブルにテスト用のユーザーを登録する。

INSERT INTO users ( user_name , password , enabled, role)
   VALUES ( 'taro', 'abcd' , 1, 'ROLE_USER' );

spring-security.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.1.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-4.0.xsd">

    <http pattern="/" security="none"/>
    <http pattern="/index.jsp" security="none"/>
    <http auto-config="true" >
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        <form-login />
        <logout />
    </http>

    <beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <beans:property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver" />
        <beans:property name="url" value="jdbc:hsqldb:hsql://localhost/mydatabase" />
        <beans:property name="username" value="sa" />
        <beans:property name="password" value="" />
    </beans:bean>

    <!-- ユーザとROLEを定義 -->
    <authentication-manager>
        <authentication-provider>
            <jdbc-user-service data-source-ref="dataSource"
                 users-by-username-query="SELECT user_name, password, enabled FROM users WHERE user_name = ?"
                 authorities-by-username-query="SELECT user_name, role FROM users WHERE user_name = ?" />
        </authentication-provider>
    </authentication-manager>
</beans:beans>