SpringSecurity 導入から基本的な認証フロー

# はじめに

Javaの学習を始めて最も躓いた`SpringSecurity`について調べ実装することができたので、記録として残しておきます。<br>完全に理解することができていない為、不備等あるかもしれませんがご了承ください。

# SpringSecurityシリーズ　項目表
|NO  |タイトル                    |
|----|--------------------------|
|その1|[SpringSecurity 導入から基本的な認証フロー](https://qiita.com/ryo0527/items/dbdbb2a476cc74e9116b)|
|その2|[SpringSecurity ログインページをカスタマイズする](https://qiita.com/ryo0527/items/2ee963cea31e82fd3dc5)|
|その3|[SpringSecurity DBアクセス処理](https://qiita.com/ryo0527/items/0b0b161530a2f0eb9e0c)|
|その4|[SpringSecurity 403エラーページをカスタマイズする](https://qiita.com/ryo0527/items/065c1a871c80e55d2935)|

# 実装

### 依存関係の追加
SpringSecurityを使うには、`spring-boot-starter-security`を追加します。
※今回はmavenでの実装とします。

```pom.xml
<!-- 中略 -->

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- 中略 -->
```

### SpringSecurity設定
`WebSecurityConfigurerAdapter`を継承したクラスを用意します。
その1ではインメモリでユーザ認証を実現します。

```java:SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Bean
  public BCryptPasswordEncoder passwordEncoder() {
    // パスワードの暗号化用に、BCrypt(ビー・クリプト)を使用
    return new BCryptPasswordEncoder();
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    // アクセス権限の設定
    http.authorizeRequests()
        // 制限なし
        .antMatchers("/").permitAll()
        // '/admin'は、'ADMIN'ロールのみアクセス可
        .antMatchers("/admin").hasRole("ADMIN")
        // 他は制限あり
        .anyRequest().authenticated();
    // ログイン処理の設定
    http.formLogin();
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    // インメモリでユーザ認証処理
    auth.inMemoryAuthentication()
        // ユーザ名'user',パスワード'user',ロール'USER'のユーザを追加
        .withUser("user").password(passwordEncoder().encode("user")).roles("USER")
        .and()
        // ユーザ名'admin',パスワード'admin',ロール'ADMIN'のユーザを追加
        .withUser("admin").password(passwordEncoder().encode("admin")).roles("ADMIN");
  }
}

```

### 画面遷移用ページの用意
ページ遷移の確認用に、必要最小限のControllerとViewファイルを用意しております。

#### Controller
```java:SecurityController
@Controller
public class SecurityController {

  @GetMapping
  public String top() {
    // top.htmlを表示
    return "top";
  }

  @GetMapping("/admin")
  public String admin() {
    // admin.htmlを表示
    return "admin";
  }

  @GetMapping("/sample")
  public String sample() {
    // sample.htmlを表示
    return "sample";
  }
}
```

#### View
```html:admin.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8">
    <title>adminページ</title>
  </head>
  <body>
    <h1>adminページ</h1>
  </body>
</html>
```

```html:sample.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8">
    <title>sampleページ</title>
  </head>
  <body>
    <h1>sampleページ</h1>
  </body>
</html>
```

```html:top.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8">
    <title>topページ</title>
  </head>
  <body>
    <h1>topページ</h1>
  </body>
</html>
```

# 動作確認
### topページ
topページは認証外としているため、未ログイン状態でも閲覧することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309433/68dbdc25-e642-0483-623a-8e6603a96777.png)


### sampleページ
sampleページはログイン状態でないと閲覧することができない。
`/sample`でsampleページを表示する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309433/d4a311ef-a4b2-eb8f-3ef4-8551ff763683.png)
未ログイン状態である為、ログインページに遷移する。（SpringSecurityのデフォルトログインページ）
フォームにユーザ名とパスワードを入力する。（今回はインメモリに設定）
すると、sampleページに遷移することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309433/f57a29da-78d0-a085-8ac0-db7e5b4bb5c8.png)

### adminページ
adminページは`ADMIN`権限が付与されたユーザのみ閲覧することができる。
`/admin`でadminページを表示する。
ADMIN権限がないユーザが閲覧するとエラーになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309433/b2d90dcd-32f2-bd3f-4e8b-29d38c8cb81e.png)

ADMIN権限を付与されたユーザでログインする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309433/0bc841f9-91f6-30e3-53d2-b7aa85bc5c9e.png)

# おまけ
SpringSecurityにデフォルトである機能
### ユーザ名、パスワード入力誤り
ユーザ名、パスワードを誤るとログインページに戻ってきてエラー表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309433/45eed381-9f91-8272-c227-f7c97f64e957.png)

### ログアウト
`/logout`でログアウトページに遷移します。（SpringSecurityのデフォルトログアウトページ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309433/9f11170d-f729-e44f-fd45-46582948ab42.png)
ボタンをクリックするとログアウトを実行して、ログインページに戻ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309433/2da08645-f410-90fe-7162-7c800c17bfcf.png)

# おわりに
これでSpringSecurityの導入から基本的な認証フローを実装することができました。
間違っている箇所ありましたら、ご指摘いただければ幸いです。
次はログインページをカスタマイズしていきます。

[その2 SpringSecurityログインページをカスタマイズする](https://qiita.com/ryo0527/items/2ee963cea31e82fd3dc5)