SpringBootのアプリにフォーム認証を追加してみた

[前回](https://qiita.com/keb/items/9b860198caf9ae7357fb)の続き

SpringBootのアプリにフォーム認証を追加してみた。

### 環境

- Mac High Sierra 10.13.5
- Java 1.8.0_11
- Maven 3.5.4
- springboot 2.0.3

### 手順

pom.xmlの設定

```pom.xml
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
	<version>2.0.3.RELEASE</version>
</dependency>
```

SecurityConfigクラス作成

- configure(WebSecurity web)では、認証しないものを設定
- configure(HttpSecurity http)では、認証関係の設定
 - index.html は認証しないようにするため、antMatchers("/").permitAll()とする
 - 認証画面は、login.htmlとしておき、loginPage("/login")とする
 - ログインが成功したときの画面は、/userとしておき、defaultSuccessUrl("/user", true)とする
 - ログアウト後の画面も、login.htmlとしておき、logoutSuccessUrl("/login")とする
- userDetailsService()でユーザID,パスワードを設定しておく
 - データベースにユーザID,パスワードを登録しておく方法もあるが、今回はInMemoryとしたので

```java:WebSecurityConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.context.annotation.Bean;
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.provisioning.InMemoryUserDetailsManager;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 認証対象外を設定
        web.ignoring().antMatchers(
                            "/assets/**",
                            "/css/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // ログイン認証を行うパスを設定
            .authorizeRequests()
                .antMatchers("/").permitAll()   // ルートは全ユーザがアクセス可能
                .anyRequest().authenticated()   // 他のURLは認証が必要
                .and()
            // フォーム認証を有効化
            .formLogin()
                .loginPage("/login")            // ログイン画面のURL
                .permitAll()                    // 全ユーザのアクセスを許可する
                .defaultSuccessUrl("/user", true)       // ログインが成功したときのURL
                .and()
            // ログアウト
            .logout()
                .logoutSuccessUrl("/login")     // ログアウト画面のURL
                .permitAll();
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        UserDetails user =
             User.withDefaultPasswordEncoder()
                // ユーザID,PassWordを設定
                .username("hoge")
                .password("hoge")
                .roles("USER")
                .build();

        return new InMemoryUserDetailsManager(user);
    }

}
```

login.htmlを作成（一部抜粋）

 - th:if="${param.error}"は認証失敗時の処理
 - <input type="email" name="username"...のnameをusernameにすることで、WebSecurityConfigの.username("hoge")と対応付ける
 - <input type="password" name="password"...こちらも同様

```java:login.html
<form class="form-signin" th:action="@{'/login'}" method="POST">
  <div th:if="${param.error}">
    <div class="alert alert-danger" role="alert">
      Invalid username or password.
    </div>
  </div>
  <label for="inputEmail" class="sr-only">Email address</label>
  <input type="email" name="username" id="inputEmail" class="form-control" placeholder="email" required autofocus>
  <label for="inputPassword" class="sr-only">Password</label>
  <input type="password" name="password" id="inputPassword" class="form-control" placeholder="password" required>
  <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
```

LoginCotroller

```java:UserController
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserController {

    @RequestMapping("/user")
    public String user() {
        return "user";
    }
}
```

あとは、user.htmlを適当に作る。