Spring Security でログイン画面を作成

- Spring Tool Suite 4 
- Java 8
- Windows 10

Spring Bootでウェブシステムを構築する際のログイン画面を作成します。
備忘のための最低限の実装となります。

## プロジェクト作成

1. プロジェクトを作成する<br>
   `ファイル > 新規 > Spring Boot > Spring スターター・プロジェクト`
1. プロジェクト作成ウィザードのプロジェクト依存関係で以下のものを選ぶ

- Spring Sequrity
- Thymeleaf
- Spring Web
- H2 Database

※今回のサンプルではデータベースは使いませんが、データベースが無いとSpring Bootが起動しないので、H2 Databaseを加えています。

それ以外は、プロジェクトに必要なものを選択します。私たちは、以下を選んだりします。

- Lombok
- Spring Boot DevTools
- Spring Data JPA
- Validation

## ログイン画面とログイン後の画面を作る

ログイン画面（LoginController)とログイン後の画面(HomeController)を作ります。

```java:LoginController
/**
 * Create: 2021/08/25
 * Copyright 2021 Sanko System Co.,Ltd.
 */
package jp.co.sankosc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class LoginController {
	
	@GetMapping("/login")
	public String login() {
		return "login";
	}
}
```

```java:HomeController
/**
 * Create: 2021/08/25
 * Copyright 2021 Sanko System Co.,Ltd.
 */
package jp.co.sankosc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {
	@GetMapping("/home")
	public String home() {
		return "home";
	}
}
```

```html:login.html
<!DOCTYPE html>
<html xmns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8"></meta>
  <title>ログイン</title>
</head>
<body>
<form method="POST" th:action="@{/login}">
  <h2>ログイン</h2>
  <p th:if="${session['SPRING_SECURITY_LAST_EXCEPTION']} != null"
  		th:text="${session['SPRING_SECURITY_LAST_EXCEPTION'].message}" class="text-danger">
  </p>
  <div>
    <label for="userid">userid</label>
    <input type-"text" name="userid" placeholder="ユーザーID" />
  </div>
  <div>
    <label for="password">password</label>
    <input type-"text" name="password" placeholder="パスワード" />
  </div>
  <div>
    <input type="submit" value="ログイン" />
  </div>
</form>
</body>
</html>
```

```html:home.html
<!DOCTYPE html>
<html xmns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8"></meta>
  <title>ホーム</title>
</head>
<body>
<form th:action="@{/logout}" method="post">
<button>ログアウト</button>
</form>
<h1>ホーム</h1>
</body>
</html>
```

## Spring Securityの設定ファイルを作る

Spring Securityの設定ファイル(SecurityConfig)を新規作成で作る

```java:SecurityConfig.java
/**
 * Create: 2021/08/25
 * Copyright 2021 Sanko System Co.,Ltd.
 */
package jp.co.sankosc.config;

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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Bean
	public BCryptPasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
	
	@Override
	public void configure(WebSecurity web) throws Exception {
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
			.antMatchers("/login").permitAll()
			.anyRequest().authenticated();
		
		http.formLogin()
			.loginProcessingUrl("/login")
			.loginPage("/login")
			.failureUrl("/login?error")
			.usernameParameter("userid")
			.passwordParameter("password")
			.defaultSuccessUrl("/home", true);
		
		http.logout()
			.logoutUrl("/logout")
			.logoutSuccessUrl("/login");
	}
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication()
			.withUser("nozaki")
				.password(passwordEncoder().encode("nozaki"))
				.roles("USER");
	}
}
```

## 実行

`実行 > Spring Boot アプリケーション`


以上となります。